wyszukiwanie plików

scenariusz: należy wyszukać na dysq wszystkie pliki o zadanych rozszerzeniach. te zindexowane i niezindexowane.

ls c:\ -recurse -force -ea silentlycontinue|?{$_.extension -match 'txt|doc|xls|pdf'}|export-csv -delimiter ';' -notype searchResults.csv

ls (get-childitem)

  • recurse: wyszukiwanie reqrsywne po wszystkich katalogach z podkatalogami
  • force: również katalogi systemowe i ukryte
  • ea: ErrorAction – wyłączenie wypluwania błędów w razie braq dostępu

match: nie trzeba podawać oddzielnie np. docx i doc, ponieważ match 'docx’ zawiera 'doc’ – to jest dopasowanie ciągu a nie równanie.

export-csv

  • delimiter: przyzwyczajenie, do przeglądania w excelu
  • notype: noTypeInformation – nie dodaje śmiecia w pierwszej linijce

eN.

podgląd eventlogu na żywo i reperacja skrzynek exchange

Windows_PowerShell_iconscenariusz

rozjechały się skrzynki na exchange. trzeba posprawdzać bazy oraz zreperować, co się da, z podglądem tego, co się dzieje w danym momencie.

podstawa

do weryfikacji i naprawy mailboxów online służy New-MailboxRepairRequest. problem polega na tym, że to polecenie nie generuje logu tylko wrzuca informacje do eventvwr. ta zmiana jest określana miałem 'alleluja, teraz jest zajebiście’ ale przeglądanie eventvwr, zwłaszcza na żywym systemie nie jest przyjemna – ani nie wiadomo kiedy co się kończy, co zaczyna, zdarzeń jest od groma, żądanie zrobione z linii poleceń, a weryfikacja w taki sposób… no generalnie słabe.

cel

byłoby fajnie móc mieć podgląd life na konsoli tego, jak przebiegają testy. zwłaszcza, jeśli chcemy co jakiś czas zapuścić weryfikację kolejnej 'podejrzanej’ skrzynki.

rozwiązanie

znalazłem w netcie kilka lamerskich skryptów, do podglądu eventvwr na żywo (-> keyword 'tail eventvwr’). czemu lamerskich? ponieważ działają na zasadzie nieskończonej pętli while($true) co już samo w sobie jest bolesne. w tej pętli co 1 sek pobierane jest ostatnie zdarzenie z logu aplikacji. czyli jeśli system jest na prawdę dociążony (a exchange potrafi taki być), może się okazać, że nie zobaczymy tego, na co czekamy. krótko mówiąc – DA SIĘ LEPIEJ (:

rozwiązaniem jest zastawienie pułapki – to nie my pytamy się logu o ostatni event, tylko niech log nam powie, że takowy się pojawił. kwestie wydajności pomijam bo nie badałem – na pewno trzeba pamiętać o wyrejestrowaniu pułapki, żeby nie dociążać systemu. mechanizmem, który to realizuje jest ’register-ObjectEvent’, który rejestruje pułapkę na przechwycenie zdarzenia dla obiektów .NET.

oczywiście nie każde polecenie zdarzenia generuje /: aby to sprawdzić, wystarczy zwykły get-member. sprawdźmy dla get-eventlog:

[PS] C:\Windows\system32>Get-EventLog -LogName application -Newest 1 |gm


   TypeName: System.Diagnostics.EventLogEntry#application/MSExchange ADAccess/1074006048

Name                      MemberType     Definition
----                      ----------     ----------
Disposed                  Event          System.EventHandler Disposed(System.Object, System.EventArgs)
CreateObjRef              Method         System.Runtime.Remoting.ObjRef CreateObjRef(type requestedTyp
Dispose                   Method         System.Void Dispose()
Equals                    Method         bool Equals(System.Diagnostics.EventLogEntry otherEntry), boo
GetHashCode               Method         int GetHashCode()
GetLifetimeService        Method         System.Object GetLifetimeService()
GetType                   Method         type GetType()
InitializeLifetimeService Method         System.Object InitializeLifetimeService()
ToString                  Method         string ToString()
Category                  Property       System.String Category {get;}
CategoryNumber            Property       System.Int16 CategoryNumber {get;}
Container                 Property       System.ComponentModel.IContainer Container {get;}
Data                      Property       System.Byte[] Data {get;}
EntryType                 Property       System.Diagnostics.EventLogEntryType EntryType {get;}
Index                     Property       System.Int32 Index {get;}
InstanceId                Property       System.Int64 InstanceId {get;}
MachineName               Property       System.String MachineName {get;}
Message                   Property       System.String Message {get;}
ReplacementStrings        Property       System.String[] ReplacementStrings {get;}
Site                      Property       System.ComponentModel.ISite Site {get;set;}
Source                    Property       System.String Source {get;}
TimeGenerated             Property       System.DateTime TimeGenerated {get;}
TimeWritten               Property       System.DateTime TimeWritten {get;}
UserName                  Property       System.String UserName {get;}
EventID                   ScriptProperty System.Object EventID {get=$this.get_EventID() -band 0xFFFF;}

no i słabo – niby jest 'disposed’ ale to nic nie daje. a to dla tego, że obiektem, który jest zwrócony, jest konkretny 'event’. jest jednak wywołanie polecenia, które 'podłącza się’ do eventlogu a nie do jego zawartości:

[PS] C:\Windows\system32>get-eventlog -List|gm


   TypeName: System.Diagnostics.EventLog

Name                      MemberType Definition
----                      ---------- ----------
Disposed                  Event      System.EventHandler Disposed(System.Object, System.EventArgs)
EntryWritten              Event      System.Diagnostics.EntryWrittenEventHandler EntryWritten(System.Object, System....
BeginInit                 Method     System.Void BeginInit()
Clear                     Method     System.Void Clear()
Close                     Method     System.Void Close()
CreateObjRef              Method     System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
Dispose                   Method     System.Void Dispose()
EndInit                   Method     System.Void EndInit()
Equals                    Method     bool Equals(System.Object obj)
GetHashCode               Method     int GetHashCode()
GetLifetimeService        Method     System.Object GetLifetimeService()
GetType                   Method     type GetType()
InitializeLifetimeService Method     System.Object InitializeLifetimeService()
ModifyOverflowPolicy      Method     System.Void ModifyOverflowPolicy(System.Diagnostics.OverflowAction action, int ...
RegisterDisplayName       Method     System.Void RegisterDisplayName(string resourceFile, long resourceId)
ToString                  Method     string ToString()
WriteEntry                Method     System.Void WriteEntry(string message), System.Void WriteEntry(string message, ...
WriteEvent                Method     System.Void WriteEvent(System.Diagnostics.EventInstance instance, Params System...
Container                 Property   System.ComponentModel.IContainer Container {get;}
EnableRaisingEvents       Property   System.Boolean EnableRaisingEvents {get;set;}
Entries                   Property   System.Diagnostics.EventLogEntryCollection Entries {get;}
Log                       Property   System.String Log {get;set;}
LogDisplayName            Property   System.String LogDisplayName {get;}
MachineName               Property   System.String MachineName {get;set;}
MaximumKilobytes          Property   System.Int64 MaximumKilobytes {get;set;}
MinimumRetentionDays      Property   System.Int32 MinimumRetentionDays {get;}
OverflowAction            Property   System.Diagnostics.OverflowAction OverflowAction {get;}
Site                      Property   System.ComponentModel.ISite Site {get;set;}
Source                    Property   System.String Source {get;set;}
SynchronizingObject       Property   System.ComponentModel.ISynchronizeInvoke SynchronizingObject {get;set;}

bingo! tu pojawia się 'entryWritten’! a więc zarejestrujmy pułapkę, przefiltrujmy zdarzenia, które nas interesują – i jeśli takowe się pojawi, wyświetlmy na ekran. opis eventów, jakie generuje new-mailboxrepairrequset można znaleźć na technecie. poniżej draft skryptu, który można sobie dowolnie rozbudować. dla czytelności zapisany w kilq linijkach.

$evtlog=Get-EventLog -list|?{$_.log -eq 'application'}

Register-ObjectEvent -InputObject $evtlog -EventName EntryWritten -SourceIdentifier EventTrap -Action{
  $id=$event.SourceEventArgs.Entry.EventID;
  if($id -gt 10041 -and $id -lt 10062) {
    write-host "$id -> $($event.SourceEventArgs.Entry.Message)"
  }
}

na początq podłączamy się do konkretnego logu – logu aplikacji. następnie dla tego logu rejestrujemy pułapkę na pojawienie się nowych zdarzeń i definiujemy akcję. ponieważ na poziomie rejestracji nie ma możliwości zdefiniowania żadnych filtrów, wszystko trzeba zdefiniować wewnątrz ciała skryptu. po dokonaniu rejestracji, w konsoli będą się pokazywać wszystkie logi pomiędzy 10041-10062. oczywiście warto je ładniej wyświetlić i zrobić pełną obsługę… aby tego dokonać, kluczowym jest obiekt $event.SourceEventArgs.Entry, który jest de facto eventem pojawiającym się w logu, czyli można dostać się do wszystkich parametrów takich jak przy ’ Get-EventLog -LogName application -Newest 1 |gm’.

na koniec trzeba pamiętać o wyrejestrowaniu!! na skróty, wyrejestrowanie wszystkich:

get-event|unregister-event

eN.

 

 

 

splatting – dynamiczna budowa parametrów wywołania

jak to często bywa, bardzo-długa-polska-nazwa ma krótki odpowiednik (; „Splatting” to mechanizm, pozwalający na zbudowanie zmiennej hashtable, która zostanie wykorzystana w miejsce tradycyjnych parametrów wywołania. po co?

bardzo często finalne parametry wywołania jakiegoś polecenia zależą od tego, co się wydarzy podczas przetwarzania skryptu. w efekcie często powstają złożone, a czasem wręcz zagnieżdżone, struktury 'if-then-else’ lub 'switch-case’. dodanie kolejnego warunku powoduje, że modyfikacja skryptu staje się nieprzyjemna lub wręcz ryzykowna, bo wymaga ciężkiego przebudowania logiki. splatting eliminuje  konieczność budowania takich dziwacznych struktur.

zademonstruję to na prostym przykładzie – założenia użytkownika. taki scenariusz: dostajemy arkusz z listą użytkowników z kilq działów. pewne dane, takie jak telefon czy adres nie są obligatoryjne i czasem są a czasem nie. w przypadq 'new-ADUser’ splatting nie pokazuje prawdziwej mocy, ponieważ większość parametrów przyjmuje '$null’ jako wartość, więc przy stałym finalnym wywołaniu, polecenie nie spowoduje błędów. ale to tylko trening:

New-ADUser -Name "test" -Path "ou=tests,dc=domain,dc=lab" -GivenName test -Surname delme
 -Company LU -Title szeregowiec -City "wąchock" -Country PL -Department IT -HomePhone $null -HomeDrive $null -HomeDirectory $null -MobilePhone $null

jest wiele poleceń, które nie będą takie przyjemne, i $null zostanie zaakceptowany lub wręcz będzie miał jakieś znaczenie. jak zatem pozbyć się takich pustych parametrów podczas przetwarzania i zbudować dynamiczną listę wywołania?

#jakiś tam import gdzie są różne informacje o nowych człowiekach
$users=import-csv -delimiter ';' -Path userFromHR.csv -encoding default

foreach($user in $users) {
    #zakładam hashtable, do którego będą zrzucane parametry wywołania.
    #przy okazji zakładam, że firma to zawsze 'logicunion' a standardową ścieżką jest jakiś kontener.
    $newUser=@{
        company='LogicUnion'
        path="ou=users,ou=central,dc=domain,dc=lab"
    }

    $newUser.Add('AccountPassword',(ConvertTo-SecureString -String "P@ssw0rd" -AsPlainText -Force) )
    $newUser.Add('EmailAddress',$user.Email)
    #teraz kilka prostych ifów które rozbudują ilość parametrów tylko jeśli będą miały jakąś wartość
    if($user.mobile) {
        $newUser.Add('mobilePhone',$user.mobile)
    }
    if($user.phone) {
        $newUser.Add('homePhone',$user.phone)
    }
    if($user.department -match 'hr' -or $user.department -match 'sales') {
        $newUser.Add('homeDrive','y:')
    }

    #no i clue - przekazanie zmiennej jako parametrów czyli SPLATTING
    New-ADUser @newUser
}

dwie ważne rzeczy:

  • przy przekazywaniu tablicy jako parametrów używa się 'at’ @ zamiast dolara '$’. dość wyjątkowe użycie – trzeba zapamiętać.
  • splatting można wykorzystać nawet tam, gdzie commandlet/funkcja nie ma zdefiniowanego przyjmowania wartości 'by value’. czyli można zawsze – to modyfikacja interpretacji polecenia a nie jego właściwego wykonania.
function test {
    param( [string]$str,[int]$i )
    echo "$str $i"
}

$params=@{
    str='abc'
    i=10
}

test @params

eN.

tablica tablic

jak w PS utworzyć tablicę tablic (np. znaków)? czyli tak, aby każdy element tablicy był kolejną tablicą znaków.

zadanie wydawałoby się trywialne… ale jest drobny myk, na którym można stracić czas. problem polega na tym, że jeśli element tablic są tego samego typu, to dodając je do tablicy, zamiast tworzyć oddzielne rekordy, są sklejane.

przykład:

C:\...ive\_scriptz :))o- $str2=1,4,6
C:\...ive\_scriptz :))o- $str1=1,4,6
C:\...ive\_scriptz :))o- $str=@()
C:\...ive\_scriptz :))o- $str+=$str1
C:\...ive\_scriptz :))o- $str+=$str2
C:\...ive\_scriptz :))o- $str
1
4
6
1
4
6
C:\...ive\_scriptz :))o- $str.length
6

czyli źle – zamiast zrobić dwuelementową tablicę, gdzie każdym elementem jest inna, 3-elementowa tablica, zostały one sklejone w 6-elementową tablicę znaków. tak samo się zachowa czy są cyfry czy znaki alfabetu. zachowanie dobre, bo zazwyczaj takiej właśnie operacji się oczeqje. ale jak zmusić aby była to tablica tablic?

trik polega na zmuszeniu PS do zrozumienia, że dodawany element ma być jako całość oddzielnym rekordem tablicy. robi się przy pomocy przecinka:

C:\...ive\_scriptz :))o- $str1=1,4,6
C:\...ive\_scriptz :))o- $str2=1,4,6
C:\...ive\_scriptz :))o- $str=@()
C:\...ive\_scriptz :))o- $str+=,$str1
C:\...ive\_scriptz :))o- $str+=,$str2
C:\...ive\_scriptz :))o- $str
1
4
6
1
4
6

C:\...ive\_scriptz :))o- $str.Length
2

C:\...ive\_scriptz :))o- $str|gm

   TypeName: System.Object[]

choć wynik wygląda pozornie tak samo, kiedy sprawdzi się ilość elementów tablicy – są dwa. get-member pokazuje, że każdy z nich jest tablicą.

eN.

 

 

Kung Fury – czyta Tomasz Knapik

oglądałem już w oryginale. film… po prostu qltowy. a już Tomasz Knapik… zaraz siadam do obejrzenia w wersji z lektorem. obowiązek dla każdego… urodzonego przed 8o’ w każdym razie, bo młodsi mogą nie do końca sqmać tą kiczowatą stylistykę. kasety VHD z wypożyczalni – po dwa filmy na taśmie, lektor, czasem tak potworny, że nie wiadomo czy się śmiać czy płakać. bruce lee, chuck norris, karate kid czy inni pijani mistrzowie, rambo i commando. w tym krótkim filmiq jest pigułka wszystkich tych filmów i jeszcze dinozaury, hitlerowcy i wikingowie, często w tym samym momencie…

eN.