Dimmo.psm1
function Get-NetworkControllerInstallationStatus { <# .SYNOPSIS This function summarizes several important configuration settings during deployment of a Network Controller VM from System Center Virtual Machine Manager (VMM). .NOTES Info from Network Controller deployment scripts PrepareNodeForNetworkController.ps1 configures: IPv6 Installation directory Certificates InstallNetworkController-AllNodes.ps1 runs: New-NetworkControllerNodeObject -Name $vmName -Server $fqdn -FaultDomain $fd -RestInterface $nicName -Verbose Install-NetworkControllerCluster -ClusterAuthentication Kerberos -ManagementSecurityGroup $mgmtSecurityGroupName -Node $nodes -CredentialEncryptionCertificate $sslCertificate -Verbose Install-NetworkController -Node $nodes -ClientAuthentication Kerberos -ClientSecurityGroup $clientSecurityGroupName -ServerCertificate $sslCertificate -RestIPAddress $restEndPoint Install-NetworkController -Node $nodes -ClientAuthentication Kerberos -ClientSecurityGroup $clientSecurityGroupName -ServerCertificate $sslCertificate -RestName $restEndPoint Install-NetworkController -Node $nodes -ClientAuthentication Kerberos -ClientSecurityGroup $clientSecurityGroupName -ServerCertificate $sslCertificate # local UITWERKEN Verify GivePermissionToNetworkService #(Get-Item -path "$ENV:ProgramData\Microsoft\Crypto\RSA\MachineKeys\*" | Get-ACL).Access | Where-Object 'IdentityReference' -EQ 'NT AUTHORITY\NETWORK SERVICE' } #Read required Get-Service SlbHostAgent # on hyper-v host server Get-Service NcHostAgent # on hyper-v host server #> param( [Parameter(Mandatory=$true)] $ComputerName ) Invoke-Command -ComputerName $ComputerName { # suppress errors because many items will not yet exist during installation $ErrorActionPreference = 'SilentlyContinue' # check computername and domain membership $Computername = Get-ChildItem Env:\COMPUTERNAME $DomainName = Get-ChildItem Env:\USERDOMAIN # verify installation folder $NCInstallDir = Get-Item 'C:\NCInstall' # verify certificate file $CertFile = Get-ChildItem -Path 'C:\NCInstall\certificate-ssl' -Filter '*.pfx' # verify IPv6: not supported by Network Controller $IPv6Config = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters\' -Name 'DisabledComponents' # -Value 0xffffffff # verify registry settings $NCReady = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\SCVMM Network Controller' -Name 'NCReady' # MarkAsReadyForNetworkControllerDeployment = 1 $NCThumbprint = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\SCVMM Network Controller' -Name 'NCThumbprint' # verify certificate installation $CertFromStore = Get-ChildItem Cert:\LocalMachine\My | Where-Object Thumbprint -EQ $NCThumbprint.NCThumbprint # Verify installation status of role $WindowsFeature = Get-WindowsFeature #-Name NetworkController, RSAT-NetworkController $NCRole = $WindowsFeature | Where-Object Name -eq 'NetworkController' $NCRSAT = $WindowsFeature | Where-Object Name -eq 'RSAT-NetworkController' # custom output $properties = [ordered]@{'DateTime' = (Get-Date -format s); 'ComputerName' = $Computername.Value; # ordered, optioneel, geef in deze volgorde terug 'DomainName' = $DomainName.Value; 'IPv6Config' = $IPv6Config.DisabledComponents; 'NCRole' = $NCReady.InstallState; 'NCRSAT' = $NCReady.InstallState; 'InstallDir' = $NCInstallDir.FullName; 'CertificateFile'= $CertFile.FullName; 'CertificateThumbprintFromStore'= $CertFromStore.Thumbprint; 'CertificateThumbprintFromRegistry' = $NCThumbprint.NCThumbprint; 'NCReady' = $NCReady.NCReady; } $output = New-Object -TypeName PSObject -Property $properties Write-Output $output } } function Get-DhcpMostRecentLease { <# .SYNOPSIS Shows most recent leases from the Microsoft DHCP Server. Requires RSAT. #> param( $ComputerName=$env:COMPUTERNAME, $Number=40 ) Get-DhcpServerv4Scope -ComputerName $ComputerName | ForEach-Object { Get-DhcpServerv4Lease -ComputerName $ComputerName -ScopeId $_.ScopeID | Sort-Object LeaseExpiryTime -Descending | Select-Object -First $Number } } function Invoke-RestMethodDemo { <# .SYNOPSIS Demonstrates REST with several public URLs. .EXAMPLE Invoke-RestMethodDemo -MetaWeather Displays weather information from metaweather.com .EXAMPLE Invoke-RestMethodDemo -RestCountries Displays country information from restcountries.eu .EXAMPLE Invoke-RestMethodDemo -LaunchLibrary Displays rocket launch information from launchlibrary.net #> param( [switch]$MetaWeather, [switch]$RestCountries, [switch]$WhereTheIssAt, [switch]$LaunchLibrary, [switch]$SpaceXData, [switch]$ipapi ) if ($MetaWeather) { Invoke-RestMethod https://www.metaweather.com/api/location/727232 } if ($RestCountries) { Invoke-RestMethod https://restcountries.eu/rest/v2/all } if ($WhereTheIssAt) { Invoke-RestMethod http://api.wheretheiss.at/v1/satellites/25544 } if ($LaunchLibrary) { Invoke-RestMethod https://launchlibrary.net/1.3/launch | Select-Object -expand Launches } if ($SpaceXData) { Invoke-RestMethod http://api.spacexdata.com/v3/launches/latest } if ($ipapi) { Invoke-RestMethod https://ipapi.co/8.8.8.8/json } } function Start-MOCLab { <# .SYNOPSIS Start required VMs for a particular lab from a MOC training (Microsoft Official Curriculum). Internet connection required. .NOTES By Dimitri Koens TO DO: implement confirm and whatif 15-04-2014: first version 16-05-2014: more generic for 10747 and 10748 and possibly other trainings, other CSV selection, sleep in variable 09-11-2015: include title in out-gridview, start hyper-v manager %windir%\system32\mmc.exe "%windir%\system32\virtmgmt.msc", run %windir%\system32\vmconnect.exe localhost 10747D-LON-CFG-A/B/C do { } while (1) 15-12-2018: more generic for most courses based on MOC material. Source CSV hosted on Github 10-01-2019: implemented -StartVMRemoteConsole #> [cmdletbinding()] param( [string]$SourceFile = 'https://raw.githubusercontent.com/Dimtemp/MOC/master/MOCLabs.csv', [switch]$StartHyperVConsole, [switch]$StartVMRemoteConsole, [int]$DCBootTimeout = 60 ) Write-Verbose "Reading $SourceFile" # moet worden -progress $WebReq = Invoke-WebRequest $SourceFile $Csv = $WebReq.Content | ConvertFrom-Csv $Training = $Csv | Select-Object MOC -Unique | Out-GridView -Title 'Select training' -OutputMode Single $Lab = $Csv | Where-Object MOC -EQ $Training.MOC | Select-Object Module, Lab, Time | Out-GridView -Title 'Select lab' -OutputMode Single $VMs = $Csv | Where-Object { $_.Module -EQ $Lab.Module -and $_.Lab -EQ $Lab.Lab } $VMs = $VMs.VMs Write-Verbose "VMs found: $VMs" $VMs = $VMs.split('/') if ($VMs.Count -lt 2) { throw "No VMs found" } if ($StartHyperVConsole) { if (Get-WmiObject win32_process | Where-Object CommandLine -match 'virtmgmt.msc') { Write-Verbose "Hyper-V console already running" } else { Write-Verbose "Starting Hyper-V console" virtmgmt.msc } } $PercentComplete = 0 $Activity = "Starting VMs for Lab {0}{1}" -f $Lab.Module, $Lab.Lab.Replace('-', '') Write-Verbose $Activity ForEach ($CurrentVM in $VMs) { Write-Progress -Activity $Activity -PercentComplete $PercentComplete -CurrentOperation $CurrentVM Write-Verbose "Starting VM $CurrentVM" $VMObject = Get-VM -Name $CurrentVM # state can be Off, Running, Saved, Paused Switch ($VMObject.State) { 'Paused' { Resume-VM -Name $CurrentVM } 'Saved' { Start-VM -Name $CurrentVM } 'Off' { Start-VM -Name $CurrentVM if ($CurrentVM -match 'DC1') { Write-Warning "Sleeping $DCBootTimeout seconds for DC to boot..." Start-Sleep $DCBootTimeout } } } if ($StartVMRemoteConsole) { Write-Verbose "Starting Virtual Machine Connection for $CurrentVM" vmconnect.exe localhost $CurrentVM } $PercentComplete += [int](100/$VMs.Count) } Write-Progress -Activity $Activity -Completed <# old function "Suspending all VM's..." # to minimize conflicts Get-VM | Where State -eq 'Running' | Suspend-VM Get-VM | Sort-Object name -Descending | ForEach-Object { start-vm ... } "Saving VMs that were previously paused..." Get-VM | Where State -eq 'paused' | Save-VM #> } function Get-Ticker { <# .SYNOPSIS Retrieves ticker info from Alpha Vantage. .EXAMPLE Get-Ticker -Ticker MSFT Gets ticker info based on symbol name. .EXAMPLE Get-Ticker -CompanyName Microsoft Gets ticker info based on Company name. .NOTES Based on https://gist.github.com/quonic/fc0a76e8a8925e91dc1937bfc19aef28 #> param( [string]$Symbol, [string]$CompanyName ) $Query = "" if ($Symbol) { $Query = $Symbol.Replace(' ', '+') } elseif ($Ticker) { $Query = $Company.Replace(' ', '+') } if (!$Query) { throw 'you must provide a value for company or symbol' } # intermediate code to retrieve symbol? $response = Invoke-WebRequest "http://d.yimg.com/autoc.finance.yahoo.com/autoc?query=$Query®ion=1&lang=en%22" $data = $response.Content | ConvertFrom-Json $ySymbol = $data.ResultSet.Result[0].symbol $data = Invoke-WebRequest "https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=$($ySymbol)&apikey=KPCCCRJVMOGN9L6T" $stockInfo = $data.Content | ConvertFrom-Json $properties = [ordered]@{ 'symbol' = $ySymbol; 'open' = $($stockInfo.'Global Quote'.'02. open') 'high' = $($stockInfo.'Global Quote'.'03. high') 'low' = $($stockInfo.'Global Quote'.'04. low') 'latestPrice' = $($stockInfo.'Global Quote'.'05. price') 'volume' = $($stockInfo.'Global Quote'.'06. volume') 'lastUpdated' = $($stockInfo.'Global Quote'.'07. latest trading day') 'close' = $($stockInfo.'Global Quote'.'08. previous close') 'priceChange' = $($stockInfo.'Global Quote'.'09. change') 'priceChangePercentage' = $($stockInfo.'Global Quote'.'10. change percent') } $output = New-Object -TypeName PSObject -Property $properties Write-Output $output # alias: echo en write, proper way to output from a function #$($stockInfo.'Global Quote'.'01. symbol') } function Measure-HashSpeed { <# .SYNOPSIS Measures the hash speed of several algorithms on a specified file. Use a large file (> 1GB) to get accurate results. #> param($filename=(throw 'you must specify a filename')) $hashes = 'SHA1', 'SHA256', 'SHA384', 'SHA512', 'MACTripleDES', 'MD5', 'RIPEMD160' $hashes | ForEach-Object { $timeTaken = (Measure-Command { Get-FileHash -Algorithm $_ -Path $filename }).TotalSeconds "{0,12}: {1,9:N5} seconds" -f $_, $timeTaken } } function Send-Tweet { <# .SYNOPSIS Sends Twitter tweets #> [cmdletbinding(SupportsShouldProcess=$true)] param ( [Parameter(Mandatory=$true)] [string]$Message, [Parameter(Mandatory=$true)] [string]$ConsumerKey, [Parameter(Mandatory=$true)] [string]$ConsumerSecret, [Parameter(Mandatory=$true)] [string]$AccessToken, [Parameter(Mandatory=$true)] [string]$AccessTokenSecret ) process { $MaxMessageLength = 280 [Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null [Reflection.Assembly]::LoadWithPartialName("System.Net") | Out-Null if ($Message.Length -gt $MaxMessageLength) { $Message = $Message.Substring(0, $MaxMessageLength-1) } Write-Verbose "Message length: $($Message.length) characters" $status = [System.Uri]::EscapeDataString($Message) $oauth_nonce = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes([System.DateTime]::Now.Ticks.ToString())) $ts = [System.DateTime]::UtcNow - [System.DateTime]::ParseExact("01-01-1970", "dd/MM/yyyy", $null).ToUniversalTime() # to do: test with diff language settings. Works with: Dutch, d-M-yyyy, location NL, non-unicode: English (US) $oauth_timestamp = [System.Convert]::ToInt64($ts.TotalSeconds).ToString() $signature = "POST&" $signature += [System.Uri]::EscapeDataString("https://api.twitter.com/1.1/statuses/update.json") + "&" $signature += [System.Uri]::EscapeDataString("oauth_consumer_key=" + $ConsumerKey + "&") $signature += [System.Uri]::EscapeDataString("oauth_nonce=" + $oauth_nonce + "&") $signature += [System.Uri]::EscapeDataString("oauth_signature_method=HMAC-SHA1&") $signature += [System.Uri]::EscapeDataString("oauth_timestamp=" + $oauth_timestamp + "&") $signature += [System.Uri]::EscapeDataString("oauth_token=" + $AccessToken + "&") $signature += [System.Uri]::EscapeDataString("oauth_version=1.0&") $signature += [System.Uri]::EscapeDataString("status=" + $status) $signature_key = [System.Uri]::EscapeDataString($ConsumerSecret) + "&" + [System.Uri]::EscapeDataString($AccessTokenSecret) $hmacsha1 = new-object System.Security.Cryptography.HMACSHA1 $hmacsha1.Key = [System.Text.Encoding]::ASCII.GetBytes($signature_key) $oauth_signature = [System.Convert]::ToBase64String($hmacsha1.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($signature))) $oauth_authorization = 'OAuth ' $oauth_authorization += 'oauth_consumer_key="' + [System.Uri]::EscapeDataString($ConsumerKey) + '",' $oauth_authorization += 'oauth_nonce="' + [System.Uri]::EscapeDataString($oauth_nonce) + '",' $oauth_authorization += 'oauth_signature="' + [System.Uri]::EscapeDataString($oauth_signature) + '",' $oauth_authorization += 'oauth_signature_method="HMAC-SHA1",' $oauth_authorization += 'oauth_timestamp="' + [System.Uri]::EscapeDataString($oauth_timestamp) + '",' $oauth_authorization += 'oauth_token="' + [System.Uri]::EscapeDataString($AccessToken) + '",' $oauth_authorization += 'oauth_version="1.0"' $post_body = [System.Text.Encoding]::ASCII.GetBytes("status=" + $status) if ($pscmdlet.ShouldProcess("$post_body", "Send-Tweet")) { try { [System.Net.HttpWebRequest] $request = [System.Net.WebRequest]::Create("https://api.twitter.com/1.1/statuses/update.json") $request.Method = "POST" $request.Headers.Add("Authorization", $oauth_authorization) $request.ContentType = "application/x-www-form-urlencoded" $body = $request.GetRequestStream() $body.write($post_body, 0, $post_body.length) } catch { Write-Warning "Something went wrong: $($error[0])" } finally { $body.flush() $body.close() $response = $request.GetResponse() Write-Output $response if ($response.statuscode -ne 'OK') { Write-Warning 'Statuscode not OK' } } } } } function Get-EventLogInterestingEvents { <# .SYNOPSIS Displays popular events from the eventlog. For example: unexpected shutdown, failed logon, account locked out. .NOTES To do: * 200 cap auth, user, ip addr, rdp gateway destination? * 300 rap auth, user, ip addr, destination * Syslog/USER32/ID 1076: reason na unexpected shutdown * Syslog/USER32/ID 1074: reason na expected shutdown * Syslog/Disk/ID 7: bad block error * Syslog/Disk/ID 51: paging warning * Syslog/Ntfs/ID 55: fs corrupt (deze zit al in Win-MP? NTFS - File System Corrupt. Event id 41??? Genereert alert???) * Applog/wininit/1001: Checking File System Occurred on Startup (zit al in Win-MP) * System log, Source: Browser, IDs: 8021, 8032 * Windows Installer installed the product, Windows (Server) Operating System, App log, 1033, WinInstaller #> param( [string]$ComputerName = $env:COMPUTERNAME, [switch]$UnexpectedShutdown, [switch]$Bootstrap, [switch]$STOPError, [switch]$FailedLogon, [switch]$AccountLockedOut, [switch]$PreAuthenticationFailed, [switch]$RDGatewayConnected, [switch]$RDGatewayFailedLogon, [switch]$RDGatewayDisconnected ) if ($UnexpectedShutdown) { Get-EventLog -ComputerName $ComputerName -LogName System -Source 'EventLog' | Where EventId -eq 6008 } if ($Bootstrap) { Get-EventLog -ComputerName $ComputerName -LogName System -Source 'EventLog' | Where EventId -eq 6009 } if ($STOPError) { Get-EventLog -ComputerName $ComputerName -LogName System -Source 'System' | Where EventId -eq 1003 } if ($FailedLogon) { Get-EventLog -ComputerName $ComputerName -LogName Security -Source 'Microsoft-Windows-Security-Auditing' | Where EventId -eq 4625 } if ($AccountLockedOut) { Get-EventLog -ComputerName $ComputerName -LogName Security -Source 'Microsoft-Windows-Security-Auditing' | Where EventId -eq 4740 } if ($PreAuthenticationFailed) { Get-EventLog -ComputerName $ComputerName -LogName Security -Source 'Microsoft-Windows-Security-Auditing' | Where EventId -eq 4771 } # werkt if ($RDGatewayConnected) { Get-EventLog -ComputerName $ComputerName -LogName 'Microsoft-Windows-TerminalServices-Gateway/Operational' -Source 'Microsoft-Windows-Security-Auditing' | Where EventId -eq 4771 } # werkt if ($RDGatewayDisconnected) { Get-EventLog -ComputerName $ComputerName -LogName 'Microsoft-Windows-TerminalServices-Gateway/Operational' -Source 'Microsoft-Windows-Security-Auditing' | Where EventId -eq 4771 } # werkt if ($RDGatewayFailedLogon) { Get-EventLog -ComputerName $ComputerName -LogName 'Microsoft-Windows-TerminalServices-Gateway/Operational' -Source 'Microsoft-Windows-Security-Auditing' | Where EventId -eq 4771 } # werkt # RD Gateway Connection Established * 302: * connect, user, ip addr, destination # RD Gateway failed logon: 304 # RD Gateway Connection disconnected 303 disco, user, ip addr, destination, xfer and rcvd bytes # Get-WinEvent [-FilterHashtable] <hashtable[]> [-MaxEvents <long>] [-ComputerName <string>] } function Get-ServiceMemoryUsage { <# .SYNOPSIS Get memory usage by service. #> param($ComputerName = $env:COMPUTERNAME) Get-WmiObject win32_service -ComputerName $ComputerName | Where-Object processid -gt 0 | foreach { $svc = $_ $getsvc = Get-Service -ComputerName $ComputerName $proc = Get-Process -ComputerName $ComputerName -id $svc.processid $props = [ordered]@{ #'ServiceDisplayName' = $svc.name; 'NPM' = $proc.NPM; 'PM' = $proc.PM; 'WS' = $proc.WS; 'ProcessName' = $proc.name; 'ServiceName' = $svc.name; 'ServiceDisplayName' = ($getsvc | Where-Object Name -eq $svc.Name).DisplayName; } New-Object -TypeName PSObject -Property $props } } function Get-AzureStackDeploymentStatus { $file = Join-Path $env:programdata 'Microsoft\AzureStack\AzureStackDeploymentStatus.xml' [xml]$asdeployfile = Get-Content $file $s1 = $asdeployfile.AzureStackDeploymentStatus.TaskGroups.TaskGroup.task do { sleep 3 [xml]$asdeployfile = Get-Content $file $s2 = $asdeployfile.AzureStackDeploymentStatus.TaskGroups.TaskGroup.task Compare-Object $s1 $s2 -Property id, status -passthru | where sideindicator -eq '=>' | foreach { Write-Host ("{0:hh:mm:ss} {1} {2}" -f (get-date), $_.id, $_.status) } $s1 = $s2 } while (1) } function Get-DuplicateFiles { <# .SYNOPSIS Generates a list of duplicate files in the current or specified directory. .DESCRIPTION Duplicate files are calculated using a filehash. This can be very time consuming and resource intensive. Only files between 1 MB and 1 GB are scanned. .EXAMPLE Get-DuplicateFiles This command scans for duplicate files in the current directory. .EXAMPLE Get-DuplicateFiles -MinimumFileSize 1KB -MaximumFileSize 1GB This command scans for duplicate files in the current directory specifying alternate file sizes. .EXAMPLE Get-DuplicateFiles -Path C:\Data -Filter *.PDF -Verbose This command scans for duplicate PDF files in the specified directory, and displays verbose output. .EXAMPLE Get-DuplicateFiles -Path C:\Data -Verbose | Export-CliXml Dups.xml This command scans for duplicate files in the specified directory, displays verbose output, and writes to a CliXml file for future reference. .EXAMPLE Get-DuplicateFiles | Out-GridView -OutputMode Multiple | Remove-Item -Confirm This command scans for duplicate files in the current directory and displays a graphical listing. Any selected files will be removed after confirmation. .LINK www.dimensionit.nl .NOTES By Dimitri Koens Contact me through: http://www.DimensionIT.nl Twitter: @DimensionIT https://twitter.com/DimensionIT Linkedin: http://nl.linkedin.com/in/dimitrikoens Facebook: http://www.facebook.com/dimitri.koens This function uses Get-FileHash function introduced in PowerShell 4. requires ps4? To do: implement workflows?, start-job? #> [CmdletBinding()] param( # Specify a path with files to be checked for duplicates. [string[]]$Path = (Get-Location), #(Get-Location).ProviderPath # Specify a filesystem filter for filenames or extensions to be checked [string]$Filter = '*', # Minimum file size to be checked. [int64]$MinimumFileSize = 1MB, # Maximum file size to be checked. Large files can take a long time to check. [int64]$MaximumFileSize = 1TB, # Different algorithms can have a huge impact on performance. SHA1 and MD5 are fast but regarded least reliable. [ValidateSet('SHA1', 'SHA256', 'SHA384', 'SHA512', 'MACTripleDES', 'MD5', 'RIPEMD160')] [string]$Algorithm='SHA256', # When specified sorts files by length ascending. [switch]$Sort # When specified will only calculate filehash on a section of the file. This can produce unreliable results. #[switch]$FastAndUnreliable #implement filter, exclude, params from get-childitem ) Write-Progress -Activity "Traversing" -CurrentOperation "$path" -Percent 0 $Files = Get-ChildItem -Path $Path -Recurse -File | Where-Object { $_.Length -ge $MinimumFileSize -and $_.Length -le $MaximumFileSize } # sort on length when required if ($Sort) { $Files = $Files | Sort-Object Length } $Files = $Files | Group-Object -Property Length | Where-Object { $_.Count -gt 1 } Write-Progress -Activity "Traversing" -CurrentOperation "Calculating total file size and number of suspects..." -Percent 80 $SuspectsFound = 0 $TotalSize = 0 $Files | Foreach { $_.Group | Foreach { $TotalSize += $_.Length $SuspectsFound++ } } Write-Progress -Activity "Traversing" -Completed Write-Verbose "$("{0:N2}" -f ($TotalSize/1GB)) GB in $SuspectsFound suspect files" # if ($FastAndUnreliable) { Write-Warning "Calculating filehash on a section of the file. This can produce unreliable results!" } $start = Get-Date $i = 0 $bytesProcessed = 0 $DuplicateFilesFound = 0 # PROCESS $Files | ForEach-Object { $_.Group | ForEach-Object { $i++ $CurrentOp = "{0} Duplicates found. File {1} of {2}, {3:N2} GB in {4}" -f $DuplicateFilesFound, $i, $SuspectsFound, ($_.length/1GB), $_.FullName # only include remaining time when reliable if ($bytesProcessed -ge 1 -and ((Get-Date)-$start).TotalSeconds -gt 3) { $TotalEstTime = ((Get-Date)-$start).TotalSeconds/$bytesProcessed*$TotalSize # in seconds $secRemaining = $TotalEstTime - ((Get-Date)-$start).totalseconds Write-Progress -Activity "Calculating hash value" -CurrentOperation $CurrentOp -Percent ($bytesProcessed/$TotalSize*100) -SecondsRemaining $secRemaining } else { Write-Progress -Activity "Calculating hash value" -CurrentOperation $CurrentOp -Percent ($bytesProcessed/$TotalSize*100) } #if ($FastAndUnreliable) { $FileHash = (Get-FileHash -Path $_.FullName -Algorithm $Algorithm).Hash # rewrite with try ... catch $_ | Add-Member -MemberType NoteProperty -Name FileHash -Value $FileHash $bytesProcessed += $_.length } # $_.Group $_.Group | Where-Object { $_.FileHash -ne $null } | # if FileHash is null file could probably not be opened for reading - filehash is still in properties, CHECK !!!!!!!!!!!!!!!!!!!!!!!! Group-Object -Property FileHash | Where-Object { $_.Count -gt 1 } | Foreach { $DuplicateFilesFound++ $_.Group # don't select, because piping to remove-item won't work anymore, use type ps1xml instead $_.Group | ForEach { Write-Debug ($("{0,12} bytes {1}" -f $_.Length, $_.FullName)) } } } # $Files Write-Progress -Activity "Calculating hash value" -Completed $TimeTaken = ((Get-Date) - $start).TotalSeconds if ($TimeTaken -lt 60) { Write-Verbose ("{0} Duplicates found, time taken: {1:N1} seconds" -f $DuplicateFilesFound, $TimeTaken) } elseif ($TimeTaken -lt 3600) { Write-Verbose ("{0} Duplicates found, time taken: {1:N1} minutes" -f $DuplicateFilesFound, ($TimeTaken/60)) } else { Write-Verbose ("{0} Duplicates found, time taken: {1:N1} hours" -f $DuplicateFilesFound, ($TimeTaken/3600)) } if ($DuplicateFilesFound -lt 1) { Write-Warning 'No duplicate files found' } } # end of function function Get-FolderSpaceReport { <# .SYNOPSIS Returns a list of total space usage per folder #> param([string]$directory='.') Get-ChildItem -Directory -Path $directory | foreach { $subfiles = Get-ChildItem $_ -Recurse $totalsize = 0 $subfiles | foreach { $totalsize += $_.length } "{0,8:N0} {1,16:N0} {2}" -f $subfiles.count, $totalsize, $_.fullname } } function Enable-RDPThroughWMI { <# .SYNOPSIS This function enables Remote Desktop connections through WMI .DESCRIPTION Remote Desktop is disabled by default. With this function you can enable Remote Desktop through the WMI interface, which is enabled by default on many Windows systems. .EXAMPLE Enable-RDPThroughWmi -ComputerName server5 This command enables Remote Desktop on server5. .EXAMPLE Enable-RDPThroughWmi -ComputerName server5 -Verbose This command enables Remote Desktop on server5 and displays verbose output. #> [cmdletbinding()]param( $ComputerName=$env:COMPUTERNAME ) Write-Verbose "Invoking WMI" Try { $cmd = "cmd /c powershell Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\' -Name 'fDenyTSConnections' -Value 0 -Force" $wmi = Invoke-WmiMethod -class Win32_process -name Create -ArgumentList $cmd -ComputerName $ComputerName -ErrorAction Stop Get-NetFirewallRule | Where-Object DisplayGroup -eq 'Remote Desktop' | Enable-NetFirewallRule # VERIFY if ($wmi.ReturnValue -eq 0) { Write-Verbose "Success. RDP is now enabled." } else { Write-Error "WMI failed. ReturnValue: $($wmi.ReturnValue)" } } Catch { Write-Error "WMI failed. Make sure Remote WMI service is running and allowed in firewall." } } function Enable-PSRemotingThroughWmi { <# .SYNOPSIS This function enables PowerShell Remoting through WMI .DESCRIPTION PowerShell Remoting is disabled by default. It can be enabled by running the command Enable-PSRemoting. With this function you can enable PowerShell Remoting through the WMI interface, which is enabled on many Windows systems. .EXAMPLE Enable-PSRemotingThroughWmi -ComputerName server5 This command enables PowerShell Remoting on server5. .EXAMPLE Enable-PSRemotingThroughWmi -ComputerName server5 -Verbose This command enables PowerShell Remoting on server5 and displays verbose output. #> [cmdletbinding()]param( $ComputerName=$env:COMPUTERNAME ) Write-Verbose "Invoking WMI" Try { $cmd = "cmd /c powershell enable-psremoting -force -skipnetworkprofilecheck && net stop WinRM && net start WinRM && net stop MpsSvc && net start MpsSvc" $wmi = Invoke-WmiMethod -class Win32_process -name Create -ArgumentList $cmd -ComputerName $ComputerName -ErrorAction Stop if ($wmi.ReturnValue -eq 0) { Write-Verbose "Success. It may take up to 60 seconds to complete..." } else { Write-Error "WMI failed. ReturnValue: $($wmi.ReturnValue)" } } Catch { Write-Error "WMI failed. Make sure Remote WMI service is running and allowed in firewall." } } function NetworkMonitor { <# .SYNOPSYS Sends a ping to all hosts on the local subnet. .DESCRIPTION This function sends a ping to all hosts on the local subnet. This is repeated every 3 seconds to monitor hosts that are coming online or are going offline. The interval is configurable through the interval parameter. .EXAMPLE NetworkMonitor This command sends a ping to all hosts with the default interval of 3 seconds. .EXAMPLE NetworkMonitor -interval 30 This command sends a ping to all hosts with an interval of 30 seconds. .EXAMPLE NetworkMonitor -noloop This command sends a ping to all hosts on the local subnet and stops. Output is pipeline-ready. .NOTES By Dimitri Koens http://www.dimensionit.nl Doesn't run on W7SP1 #> [cmdletbinding()]param ( [int]$interval=3, [switch]$noloop ) function Get-IPrange { param ( [string]$start, [string]$end, [string]$ip, [string]$mask, [int]$cidr ) function IP-toINT64 () { param ($ip) $octets = $ip.split(".") return [int64]([int64]$octets[0]*16777216 +[int64]$octets[1]*65536 +[int64]$octets[2]*256 +[int64]$octets[3]) } function INT64-toIP() { param ([int64]$int) return (([math]::truncate($int/16777216)).tostring()+"."+([math]::truncate(($int%16777216)/65536)).tostring()+"."+([math]::truncate(($int%65536)/256)).tostring()+"."+([math]::truncate($int%256)).tostring() ) } if ($ip) {$ipaddr = [Net.IPAddress]::Parse($ip)} if ($cidr) {$maskaddr = [Net.IPAddress]::Parse((INT64-toIP -int ([convert]::ToInt64(("1"*$cidr+"0"*(32-$cidr)),2)))) } if ($mask) {$maskaddr = [Net.IPAddress]::Parse($mask)} if ($ip) {$networkaddr = new-object net.ipaddress ($maskaddr.address -band $ipaddr.address)} if ($ip) {$broadcastaddr = new-object net.ipaddress (([system.net.ipaddress]::parse("255.255.255.255").address -bxor $maskaddr.address -bor $networkaddr.address))} if ($ip) { $startaddr = IP-toINT64 -ip $networkaddr.ipaddresstostring $endaddr = IP-toINT64 -ip $broadcastaddr.ipaddresstostring } else { $startaddr = IP-toINT64 -ip $start $endaddr = IP-toINT64 -ip $end } for ($i = $startaddr; $i -le $endaddr; $i++) { INT64-toIP -int $i } } # function get-iprange function PingAsync { param($ComputerName) $t=$ComputerName | foreach { (New-Object Net.NetworkInformation.Ping).SendPingAsync($_,250) } [Threading.Tasks.Task]::WaitAll($t) $t.Result } Write-Host "NetworkMonitor: ping entire subnet, use with care! (interrupt with Ctrl-C)" -ForegroundColor Cyan $netip = Get-NetIPAddress -AddressFamily ipv4 | Where-Object ipaddress -notmatch '127\.0\.0\.1' # exclude apipa range: |169\.254\. if ($netip.count -gt 1) { $netip = $netip | Out-GridView -OutputMode single -Title 'Select an IP address' } $ips = Get-IPrange -ip $netip.IPAddress -cidr $netip.PrefixLength $ips = $ips[1..($ips.count-2)] # exclude network address and broadcast address if ($ips.count -gt 256) { Write-Warning "IP Range very large!" } Write-Host ("{0:hh:mm:ss} Sending initial ping to {1} addresses... " -f (get-date), $ips.count) -NoNewline $res1 = PingAsync $ips Write-Host "$(($res1 | Where-Object Status -eq 'Success').count) IP addresses responding" if (!$noloop) { $res1 | Where-Object Status -eq 'Success' | foreach { Write-Host ("{0:hh:mm:ss} {1,-15} is responding" -f (get-date), $_.address) -foregroundcolor green } } else { $res1 | Where-Object Status -eq 'Success' | Select-Object Status, Address, RoundtripTime } while(!$noloop) { Start-Sleep $interval $res2 = PingAsync $ips Compare-Object $res1 $res2 -Property status, address -passthru | foreach { if ($_.sideIndicator -eq "=>" -and $_.status -eq 'success') { Write-Host ("{0:hh:mm:ss} {1,-15} is responding" -f (get-date), $_.address) -foregroundcolor green } # success if ($_.sideIndicator -eq "<=" -and $_.status -eq 'success') { Write-Host ("{0:hh:mm:ss} {1,-15} is not responding" -f (get-date), $_.address) -foregroundcolor yellow } # prev success } # foreach $res1 = $res2 } # while } # function function ProcessMonitor { <# .SYNOPSIS Displays changes in the process list on this or a remote PC. .DESCRIPTION Great for monitoring logon/startup scripts, batch jobs, software installations, etc... Especially on terminal servers. Works for local and remote computers. .EXAMPLE ProcessMonitor Compares changes in the process list every second on the local computer. .EXAMPLE ProcessMonitor -Interval 30 Compares changes in the process list for every 30 seconds. .EXAMPLE ProcessMonitor -Computername ServerB Compares changes in the process list on ServerB. .NOTES Created by Dimitri Koens, www.dimensionit.nl Version 1.3: display current time when results in compare are empty Version 1.4: commandlineWidth implemented Next version: adapt for ISE #> param([int]$Interval=1, [string]$Computername='.') Write-Host "ProcessMonitor (interrupt with Ctrl-C)" -ForegroundColor Cyan $minimumWidth = 40 $refProcs = Get-WmiObject win32_process -ComputerName $Computername Do { Start-Sleep $Interval $diffProcs = Get-WmiObject win32_process -ComputerName $Computername $result = Compare-Object $refProcs $diffProcs -Property ProcessId -passthru $result | foreach { # construct primary string $msg = "{0:hh:mm:ss} {1,5} pid {2,15} " -f (Get-Date) , $_.ProcessId, $_.Name # construct rest of string, .commandline also contains .path $commandlineWidth = $Host.UI.RawUI.WindowSize.Width - $msg.Length # measure everty time to address screen resize If ($commandlineWidth -lt $MinimumWidth) { $commandlineWidth = $MinimumWidth } If ($_.commandline.length -lt $commandlineWidth) { $msg = $msg + $_.commandline } else { $msg = $msg + $_.commandline.SubString(0,$commandlineWidth-1) } if ($_.sideIndicator -eq "=>") { Write-Host $msg -foregroundcolor green } # new process running if ($_.sideIndicator -eq "<=") { Write-Host $msg -foregroundcolor yellow } # existing process stopped } # foreach if ($result -eq $null) { $msg = "{0:hh:mm:ss}" -f (Get-Date) Write-Host -NoNewline $msg $Host.UI.RawUI.CursorPosition = New-Object System.Management.Automation.Host.Coordinates 0,($Host.UI.RawUI.CursorPosition.y) } $refProcs = $diffProcs } while (1) } # function function ServiceMonitor { <# .SYNOPSIS Displays changes in services list .DESCRIPTION version 1.0 .EXAMPLE ServiceMonitor Compares changes in the services list every second on the local computer or remote computers. .EXAMPLE ServiceMonitor -Interval 30 Compares changes in the services list for every 30 seconds. .NOTES Niet te zien of een service wijzigt of nieuw is #> param($computername='localhost', [int]$Interval = 1) Write-Host "ServiceMonitor (interrupt with Ctrl-C)" -fore cyan $svcBaseline = Get-Service -computername $computername Do { Start-Sleep $Interval $svcCurrent = Get-Service -computername $computername Compare-Object $svcBaseline $svcCurrent -Property machinename, name, displayname, status | where { $_.sideindicator -eq '=>' } | foreach { $msg = "{0:hh:mm:ss} {1} {2} ({3})" -f (get-date) , $_.machinename, $_.name, $_.displayname if ($_.status -eq "running") { Write-Host $msg -foregroundcolor green } # service started if ($_.status -eq "stopped") { Write-Host $msg -foregroundcolor yellow } # service stopped } # foreach $svcBaseline = $svcCurrent } while ( 1 -eq $true) } # function function EventLogMonitor { param( $Log='system' , $computername='.', $interval =1, $window= 100, $color="cyan" ) # nog verwerken: echo $log tijdens init # nog verwerken: echo warning over breedte van console # nog verwerken: afbreken einde regel werkt niet goed <# .SYNOPSIS Monitors the eventlog for new entries and displays them on screen. .DESCRIPTION With this tool you can monitor the eventlog for new entries as they occur. Great for troubleshooting. #> # security events opsommen, ook over rdp # scom acs kevin holman # ook mogelijk om ipv compare een where te doen icm index property, maar dan misschien moeilijker werkend te maken over meerdere computers $MinimumWidth = 160 function GetEventLogFromMultipleComputers { $tmpEvents = @() # array leegmaken foreach ($computer in $computername) { $tmpEvents += Get-EventLog $Log -newest $window -ComputerName $computer } $tmpEvents | sort timegenerated # need to sort because output is chronological and default sort is probably by machinename } function SimplifyEventLogMessage { param([string]$Message) $returnmessage = "" Foreach ($line in $message) { $returnmessage += $line.ToString() } $returnmessage = $returnmessage.replace([char]10, " ").replace([char]13, " ").replace(" ", " ").replace(" ", " ").replace(" ", " ") if ($returnmessage.length -ge $width) { $returnmessage.SubString(0,$width) } else { $returnmessage } # if ($returnmessage.length -gt $width) { $returnmessage = $returnmessage.SubString(0,$width) } # $returnmessage } Write-Host "EventLog Monitor v1.0" -foregroundcolor cyan If ($computername.count -gt 1) { "running across $($computername.count) computers: $computername" } Write-Warning "Events will not show up when source computers log more than $window events in $interval seconds" $Width = $Host.UI.RawUI.WindowSize.Width - 30 If ($Width -lt $MininmumWidth) { $Width = $MinimumWidth; Write-Warning "Output width set to $Width" } write-progress -Activity 'reading eventlog' $a = GetEventLogFromMultipleComputers write-progress -activity 'reading eventlog' -Completed Do { Sleep $interval $b = GetEventLogFromMultipleComputers Compare-Object $a $b -Property MachineName, Index -passthru | where { $_.sideindicator -eq "=>" } | foreach { if ($_ -ne $null) { if ($_.MachineName.length -gt 15) { $MachineName = $_.MachineName.SubString(0,15) } else { $MachineName = $_.MachineName } $msg = "{0,15} {1:HH:mm:ss} {2,6} {3} | {4}" -f $MachineName, $_.TimeGenerated, $_.EventID, $_.Source, (SimplifyEventLogMessage $_.Message) # colored output switch ($_.entrytype) { 'error' { Write-Host $msg -foregroundcolor 'red' } 'warning' { Write-Host $msg -foregroundcolor 'yellow' } Default { Write-Host $msg -foregroundcolor 'cyan' } } } } # foreach $a = $b } while ( 1 -eq $true) } function FolderMonitor { <# .SYNOPSIS Displays changes in a folder .DESCRIPTION version 1.1 .EXAMPLE FolderMonitor C:\SCCMContentlib, C:\SMSPKG, 'C:\SMSPKGC$', C:\SMSPKGSIG, 'C:\SMSSIG$' Compares changes in the specified folders every second on the local computer. #> [cmdletbinding()]param( [string[]]$folder, # required [int]$Interval = 1 # to do: force, recurse, output to address specific changes (mode, length, lastwritetime) ) Write-Host "FolderMonitor, interrupt with Ctrl-C, inspecting $folder" -ForegroundColor cyan $f1 = Get-ChildItem -path $folder -Force -Recurse Write-Verbose "$($f1.count) items found" Do { Start-Sleep $Interval $f2 = Get-ChildItem -path $folder -Force -Recurse Compare-Object $f1 $f2 -Property name, mode, length , lastwritetime -passthru | foreach { $msg = "{0} {1} {2} {3}" -f $_.mode, $_.lastwritetime, $_.length, $_.fullname if ($_.sideindicator -eq "=>") { Write-Host $msg -foregroundcolor green } if ($_.sideindicator -eq "<=") { Write-Host $msg -foregroundcolor yellow } } # foreach $f1 = $f2 } while (1) } # function function Send-WakeOnLan { <# .DESCRIPTION Enter MAC Address in the following form: 00-00-00-00-00-00 or 00:00:00:00:00:00 .NOTES A Magic Packet is a broadcast frame containing anywhere within its payload 6 bytes of all 255 (FF FF FF FF FF FF in hexadecimal), followed by sixteen repetitions of the target computer's 48-bit MAC address, for a total of 102 bytes (source: Wikipedia) Troubleshooting: uitsluitend wol indien pc uitstaat dmv softknop (oftewel: dient al eens aangestaan hebben) To do: retrieve mac addresses from dhcp To do: accept DHCP leases as pipeline input to do: param macaddress throw 'verplicht' #> [cmdletbinding()]param( [string[]]$MacAddress, [int]$repeat=1, [int]$interval=1 ) $MacAddress = $MacAddress.Split('-').Split(':' ) $formattedMacAddress = $MacAddress | foreach { [System.Convert]::ToByte($_ ,16) } # constructing magic packet $packet = [byte[]](,0xFF * 102) # construct 102 bytes of FF 6..101 | foreach { $packet[$_] = [byte]$formattedMacAddress[($_%6)] } $UDPclient = New-Object System.Net.Sockets.UdpClient $UDPclient.Connect(([System.Net.IPAddress]::Broadcast), 4000) for ($i=0; $i -lt $repeat; $i++) { Write-Output ("{0:HH:mm:ss} Sending wake-up packet to {1}" -f (Get-Date), "$MacAddress") # preferred to output '-' seperated $result = $UDPclient.Send($packet, $packet.Length) # result: number of bytes sent if ($result -ne 102) { Write-Error "Something went wrong: $result bytes sent" } if ($i -lt $repeat-1) { Start-Sleep $interval } } $UDPclient.Close() # finalize? dispose? :( } function MultiPing { <# .SYNOPSIS Sends a ping to a specified host or several hosts. Colors the output to indicate latency. .DESCRIPTION Provides a simple network monitoring solution, without the need to install any software. .EXAMPLE MultiPing ServerX Sends a ping to ServerX every second. Repeats forever. .EXAMPLE MultiPing ServerX, ServerY, 10.1.1.254, www.google.com Sends a ping to two servers, the IP address of the default gateway and a webserver on the internet .NOTES Update jul 2016: Timestamp included. #> param( [string[]]$computername=$Env:COMPUTERNAME, [switch]$ExcludeTimeStamp=$false, [switch]$ExcludeDefaultGateway=$false, [switch]$NoRepeat=$false, [int]$PingCritical=100, [int]$PingWarning=10, [int]$Delay=1000 ) if ($ExcludeDefaultGateway -eq $false) { $gw = Get-WmiObject Win32_NetworkAdapterConfiguration | Where { $_.IPEnabled -and $_.DefaultIPGateway -ne $null } | Select -expand DefaultIPGateway $computername += $gw } Write-Host "Pinging $($computername.count) remote systems. Interrupt with Ctrl-C. v1.2" -Foregroundcolor cyan Write-Host "Delay: $Delay ms. Thresholds: critical=$PingCritical, warning=$PingWarning" -Foregroundcolor cyan $i = 0 # line numbers Do { $height = $host.ui.RawUI.WindowSize.Height - 2 if ($height -lt 5) { $height = 5 } # height = 0 in ISE $TimeStamp = "{0:HH:mm}" -f (Get-Date) # write the header if ([int]($i / $height) -eq ($i / $height)) { if (!$ExcludeTimeStamp) { Write-Host "time " -NoNewline } Write-Host " $computername" } if (!$ExcludeTimeStamp) { Write-Host $TimeStamp -NoNewline } $computername | foreach { $a = Test-Connection $_ -Count 1 -ErrorAction SilentlyContinue if (!$?) { $msg = "---".PadLeft($_.length) + " " Write-Host $msg -NoNewline -ForegroundColor red } else { $msg = "$($a.ResponseTime.ToString().Padleft($_.length)) " # used $($a.Address) to write hostname on screen if ($a.ResponseTime -ge $PingCritical) { write-host $msg -nonewline -fore red } elseif ($a.ResponseTime -ge $PingWarning) { write-host $msg -nonewline -fore yellow } else { write-host $msg -nonewline } } } $i++ Write-Host "" # read the keyboard. Q = quit. #$key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") #if ($key.Character -eq 'q') { $NoRepeat = $true } if (!$NoRepeat) { Start-Sleep -Milliseconds $Delay } # perform delay only when repeat is true } while (!$NoRepeat) # exit loop after first round when -NoRepeat is specified } function Get-MessageOfTheDay { $msg = "Knowledge is power", "Power is the ultimate aphrodisiac", "With great power comes great responsibility", "If computers get too powerful, we can organize them into a committee -- that will do them in.", "Nearly all men can stand adversity, but if you want to test a man's character, give him power.", "Never go backward. Attempt, and do it with all your might. Determination is power.", "Power is like being a lady... if you have to tell people you are, you aren't.", "Power is always dangerous. Power attracts the worst and corrupts the best.", "There are 10 types of people who understand binary: those who do and those who don't.", "I'm sure the universe is full of intelligent life. It's just been too intelligent to come here.", "If you think it's expensive to hire a professional, wait until you hire an amateur", "Why is it drug addicts and computer afficionados are both called users?", "Progress isn't made by early risers. It's made by lazy men trying to find easier ways to do something.", "That's the thing about people who think they hate computers... What they really hate are lousy programmers.", "Man is the best computer we can put aboard a spacecraft... and the only one that can be mass produced with unskilled labor.", # Wernher von Braun "Man is a slow, sloppy and brilliant thinker; the machine is fast, accurate and stupid.", # William M. Kelly "Old programmers never die... They just decompile.", # Peter Dick "Walking on water and developing software from a specification are easy if both are frozen." # Edward V. Berard, # select a random message $msg[(random($msg.length))] } Set-Alias motd Get-MessageOfTheDay function Invoke-Speak { <# .Synopsis Reads text through the default speakers .DESCRIPTION Long description .EXAMPLE Invoke-Speach This command reads an inspiring message through the default speakers .EXAMPLE Invoke-Speach -Volume 50 -Rate 1 "Nearly all men can stand adversity, but if you want to test a man's character, give him PowerShell!" Another example of how to use this cmdlet .EXAMPLE "Never go backward. Attempt, and do it with all your might. Determination is power." | Invoke-Speach A string being passed through the pipeline will be spoken .EXAMPLE The measure of a man is what he does with PowerShell | say Example of the use of the alias .NOTES Verbs that apply: Out, Invoke, Read #> [CmdletBinding()] Param ( # The sentence or word that is being spoken [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)] [string] $Sentence='With great power comes great responsibility', # Volume between 0 and 100, default is 100 [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=1)] [int] $volume=100, # The rate, or speed of the sentence that's being spoken. -10 is extremely slow, 10 is extremely fast, 0 is the default. [int] $rate=0, # The voicenumber that is found on the system, default is 0 [int] $VoiceNumber=0 ) Begin { $a = New-Object -ComObject SAPI.SpVoice $a.Volume = $Volume $a.Rate = $Rate $a.voice = ($a.GetVoices[$VoiceNumber]) } Process { $a.speak($sentence) } End { $a = $null } } Set-Alias say Invoke-Speak # Export-ModuleMember -Alias * -Cmdlet * -Function * -Variable * |