Get-Aduser -Filter non accetta una variabile

Vorrei verificare se esiste già un account utente nel sistema.

$SamAc = Read-Host 'What is your username?' $User = Get-ADUser -Filter {sAMAccountName -eq "$SamAc"} 

Non sono sicuro del perché, ma $User restituirà sempre null anche se {sAMAccountName -eq "$SamAc"} dovrebbe essere vero.

Cosa mi manca qui?

Modificare:

Questo è ciò che mancava:

 $User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'" 

Nota del redattore: il blocco di script ( { ... } ) è stato sostituito con una stringa .

    Ci sono informazioni preziose nelle risposte esistenti, ma penso che un riassunto più focalizzato sia utile:

    tl; dr

    • NON utilizzare MAI un blocco di script{ ... } per build un argomento -Filter -parameter, per qualsiasi cmdlet .

      • Funziona solo in circostanze molto limitate – vedi sotto.
      • Dà l’impressione errata che il filtro sia un pezzo di codice PowerShell , che non lo è (supporta solo alcuni operatori il cui comportamento in parte è diverso dalla controparte di PowerShell – vedi Get-Help about_ActiveDirectory_Filter ).
    • Utilizzare SEMPRE una stringa per build un argomento -Filter -parameter, perché il tipo effettivo del parametro è [string]

      • Nel caso in esame: Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
      • Vedi Get-Help about_ActiveDirectory_Filter

    L’ approccio corretto e robusto è build una stringa

    • Qualsiasi argomento passato a -Filter viene prima forzato a una stringa , prima che venga passato al cmdlet Get-ADUser , perché il parametro -Filter è di tipo [string] – su tutti i cmdlet che supportano questi parametri; verificare con Get-ADUser -?

    • Con -Filter in generale, spetta al cmdlet interpretare quella stringa, utilizzando un linguaggio specifico del dominio che spesso ha poco in comune con PowerShell .

      • Nel caso di Get-ADUser , quella lingua specifica del dominio (linguaggio di query) è documentata in Get-Help about_ActiveDirectory_Filter

    Usa l’ interpolazione di stringhe di PowerShell (o concatenazione di stringhe da valori letterali e riferimenti / espressioni variabili) per “infornare” qualsiasi riferimento di variabile nella stringa , in primo piano .

    Ad esempio, i seguenti comandi funzionano tutti e sono funzionalmente equivalenti, utilizzando varie tecniche di PowerShell per build la stringa, con variazioni negli stili di quotatura e nel carattere di escape:

     # All these commands are equivalent. Get-ADUser -Filter "sAMAccountName -eq ""$SamAc""" Get-ADUser -Filter "sAMAccountName -eq `"$SamAc`"" #` Get-ADUser -Filter "sAMAccountName -eq '$SamAc'" Get-ADUser -Filter ('sAMAccountName -eq "' + $SamAc + '"') 

    La parte importante è assicurarsi che $SamAc venga espanso in anticipo (sostituito dal suo valore), tramite una stringa con doppia virgoletta "..." o mediante una concatenazione di stringhe esplicite ( + $SamAc + ... ).

    Se $SamAc contiene jdoe per esempio, i comandi sopra passano uno dei seguenti (equivalenti) valori letterali a -Filter :

     sAMAccountName -eq "jdoe" sAMAccountName -eq 'jdoe' 

    Tuttavia, con tipi di dati diversi da numeri e stringhe , potrebbe essere comunque necessario utilizzare la valutazione delle variabili del provider AD (vedere di seguito):

    Ad esempio, un valore [datetime] stringhe (es., 08/15/2018 12:45:58 ) potrebbe non essere riconosciuto come data dal provider AD [1] .

    In quell’evento:

    • Usa una stringa a valore unico ( '...' )
    • Assicurati di utilizzare solo riferimenti variabili semplici (ad es. $date ), non espressioni ( $date.Year o $($date.Year) ); per esempio:
     # Note the use of '...' and be sure to use just a variable reference, # not an expression. # With this approach, never use embedded quoting, even with string variables. Get-ADUser -Filter 'whenChanged -ge $date' 

    Avvertenza : questo approccio non funziona con moduli remoti implicitamente , poiché il riferimento variabile viene quindi valutato sulla macchina remota .


    Se si specifica un blocco di script , che si dovrebbe evitare :

    Un blocco di script, quando viene convertito in una stringa, restituisce il contenuto letterale tra { e }nessuna espansione variabile (interpolazione) ha luogo:

      PS> {sAMAccountName -eq "$SamAc"}.ToString() sAMAccountName -eq "$SamAc" # !! $SamAc was *not* expanded 

    Pertanto, è letteralmente sAMAccountName -eq "$SamAc" passato a Get-ADUser .

    Get-ADUser , forse nel tentativo di supportare la syntax del blocco di script / essere più simile a PowerShell, supporta il riferimento a una variabile non quotata , notare l’assenza di " intorno a $SamAc :

     { sAMAccountName -eq $SamAc } # as stated, Get-ADUser doesn't see the { and } 

    Get-ADUser dire, Get-ADUser fa la sua interpretazione, simile a Powershell, dello string letterale sAMAccountName -eq $SamAc : proprio come non è necessario racchiudere una variabile di riferimento in "..." in un’espressione di PowerShell (ad esempio, 'Windows_NT' -eq $env:OS ), non è necessario che qui – e in realtà non deve , come evidenziato dal tentativo fallito dell’OP.

    Tuttavia, questa emulazione di un normale blocco di script di PowerShell non è solo confusa – perché gli utenti pensano ancora che debbano racchiudere le virgolette – ma anche mezzo cotto e quindi fragile :

    • Non funziona con riferimenti di proprietà o chiamate di metodi :

       { sAMAccountName -eq $searchObj.SamAccountName } # !! DOES NOT WORK 
    • Non funziona con moduli remoti implicitamente , perché il riferimento variabile viene valutato sulla macchina remota , cercando la variabile.


    La fonte della confusione del blocco di script

    Mentre:

    • Get-Help about_ActiveDirectory_Filter parla solo di corde ,

    • è Get-Help Get-ADUser che, purtroppo, utilizza blocchi di script per tutti i suoi esempi .

    Con una eccezione, gli esempi usano solo letterali all’interno dei blocchi di script, dove il problema non emerge mai. Quell’unica eccezione (al momento in cui scrivo) è:

     -filter { lastLogon -le $logonDate } 

    Questo esempio funziona – utilizza un riferimento di variabile semplice senza virgolette – ma, a causa della scelta di un valore non stringa , nessuno è tentato di applicare erroneamente virgolette racchiuse in questo caso, diversamente dal confronto tra i campi stringa .

    La syntax del blocco di script è seducente e comoda , perché la citazione diventa più semplice: non hai bisogno di virgolette nidificate .
    Tuttavia, per tutte le ragioni discusse dovrebbe essere evitato.


    [1] Se qualcuno potesse verificare ciò, sarebbe grandioso (io personalmente non posso): l’equivalente di string-expansion-up-front dell’istruzione provider-variable-by-AD-variable
    Get-ADUser -Filter 'whenChanged -ge $date'
    è
    Get-ADUser -Filter "whenChanged -ge '$date'"
    il che significa che il provider AD in definitiva vede qualcosa di simile
    whenChanged -ge '01/15/2018 16:00:00'
    come espressione del filtro; affinché questo funzioni, dovrebbe (a) accettare una stringa come operando, e (b) comprendere il formato data / ora di PowerShell, che è il formato della cultura invariabile (date simili agli Stati Uniti con il mese elencato per primo, ma 24 -ora orologio).
    Lo fa?

    Questo un po ‘me quando ho iniziato a lavorare con il modulo ActiveDirectory, ed era un dolore da capire.

    Il parametro -Filter per i cmdlet del modulo ActiveDirectory è in realtà in cerca di una stringa. Quando si esegue {sAMAccountName -eq "$SamAc"} come valore, in realtà sta cercando "sAMAccountName -eq ""`$SamAc"""

    Fondamentalmente, Powershell analizza il parametro e trasforma il suo valore in una stringa e non interpola la variabile. Prova a build la stringa in anticipo e dovrebbe funzionare.

    Qualcosa come questo:

     $SamAc = Read-Host 'What is your username?' $filter = "sAmAccountname -eq ""$SamAc""" $User = Get-ADUser -Filter $filter 

    Devo commentare su questo perché mi ha davvero esasperato risolvere questo problema.

    Joseph Alcorn ha l’idea giusta. Il parametro filter prende una stringa e poi la valuta per elaborare il filtro. Ciò che fa scattare le persone con questo è che ti viene data l’opzione di usare parentesi graffe invece {}, e questo non funziona come ti aspetteresti se stavi usando Dove … deve ancora essere trattato come una stringa.

     $SamAc = Read-Host 'What is your username?' $User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'" 

    Raccomando di attenermi alle virgolette per renderlo più chiaro / leggibile per te stesso e gli altri e per evitare potenziali errori di syntax, o attenersi a Where {} nella pipeline. Quando lo faccio, trovo il modo migliore di usare le virgolette sul lato esterno e le virgolette singole all’interno così da ottenere comunque il riconoscimento intellisense sulla variabile.

    Basta rimuovere le virgolette attorno alla tua variabile:

    $SamAc = Read-Host 'What is your username?'

    $User = Get-ADUser -Filter {sAMAccountName -eq $SamAc}

    Questo dovrebbe funzionare bene.

     if (($ADUser = Get-ADUser -filter "SamAccountName -eq '$(Read-Host Username)'") -ne $null) {$ADUser.SamAccountName} else {"Not Found"} 

    Ok, ho finalmente il mio a lavorare usando la seguente syntax e usando il seguente esempio da sopra:

    In precedenza:

     $User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'" 

    Versione di lavoro:

     $user = Get-aduser -Filter "sAMAccountName -eq '$($SamAc)'" 

    Ho dovuto aggiungere $ ($) a $ SamAc prima che PowerShell potesse accedere al valore di stringa variabile.

    Spero che questo aiuti qualcuno!