├── .gitignore ├── Add-RsToSubVs.ps1 ├── AudioCodesCdr.ps1 ├── AudioCodesIPPhone.ps1 ├── Compare-FileHash.ps1 ├── CryptoTools.ps1 ├── ExDagMaintenance └── ExDagMaintenance.psm1 ├── ExVirtualDir.ps1 ├── Exchange_TimeBasedInboxRule.ps1 ├── Find-UniqueIP.ps1 ├── Get-AdAuditReport.ps1 ├── Get-DiskSpaceReport.ps1 ├── Get-ExVirtualDirectory.ps1 ├── Get-InventoryInfo.ps1 ├── Get-TeamsNetAssessmentStats.ps1 ├── GitHub.ps1 ├── Invoke-DiskSpd.ps1 ├── Invoke-SEFAUtil.ps1 ├── Invoke-VocabTrainer.ps1 ├── M01Stats.ps1 ├── Microsoft.PowerShell_profile.ps1 ├── Microsoft.PowerShell_profile_osx.ps1 ├── New-FirewallRule.ps1 ├── New-SfBBackup.ps1 ├── README.md ├── Read-GPG.ps1 ├── Remove-LogFile.ps1 ├── Restore-VMPermission.ps1 ├── Restore-VmPermission.Tests.ps1 ├── Send-MailJetMail.ps1 ├── Send-SplunkEvent.ps1 ├── Start-ArchiveLog.ps1 ├── Start-OutlookBackup.ps1 ├── Start-TestWebServer.Tests.ps1 ├── Start-TestWebServer.ps1 ├── Telegram.ps1 ├── Test-GroupMembership.ps1 ├── Untitled-2.ps1 ├── Untitled-4.ps1 ├── Update-DashboardInfo.ps1 ├── WordPressApiDemo.ps1 ├── bv-calc.ps1 ├── chromecast.ps1 ├── compare-directory.ps1 ├── ews.ps1 ├── exchange.ps1 ├── get-sfbconnections.ps1 ├── ifttt.ps1 ├── kraken-stats.ps1 ├── logmytime.ps1 ├── new-cap.ps1 ├── nostr.ps1 ├── npslog.ps1 ├── prtg.ps1 ├── pskeybase.ps1 ├── qos.ps1 ├── rgsreport-xml.ps1 ├── sqltools.ps1 ├── tak.Import-NPSLog.ps1 ├── test-exchangeautodisco.ps1 ├── uccapilog.ps1 └── vmware.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /Add-RsToSubVs.ps1: -------------------------------------------------------------------------------- 1 | function Add-RsToSubVs { 2 | <# 3 | .Synopsis 4 | Add a Real Server to one or more sub virtual services on a KEMP load balancer. 5 | .DESCRIPTION 6 | This function calls Send-LBMessage to add a Real Server to sub virtual services. 7 | A filter for the virtual services nickname can be used in order to add the real server 8 | to multiple sub VS matching the filter. Alternatively, the function takes objects returned 9 | from Get-VirtualService and adds the real server to each returned VS. 10 | .EXAMPLE 11 | Add-RsToSubVs -SubVsFilter "Exchange 2013*" -RealServer 192.168.1.1 -Port 443 12 | 13 | This example adds RS 192.168.1.1:443 to all sub virutal services matching the name "Exchange 2013*" 14 | .EXAMPLE 15 | Get-VirtualService | Where-Object {$_.nickname -like "Exchange 2013*"} | Add-RsToSubVs -RealServer 192.168.1.1 -Port 443 -Weight 2000 16 | 17 | This example adds RS 192.168.1.1:443 to all virtual services returned by Get-VirtualService and the following filter. 18 | Please note: Get-VirtualService returns only sub virtual services, no addtional filtering is done. 19 | .INPUTS 20 | This cmdlet takes input objects from Get-VirtualService 21 | #> 22 | [CmdletBinding(SupportsShouldProcess=$true, 23 | ConfirmImpact='High')] 24 | param( 25 | [Parameter(Mandatory=$true, 26 | ValueFromPipelineByPropertyName=$true, 27 | ParameterSetName='Index')] 28 | [int] 29 | $Index, 30 | 31 | [Parameter(Mandatory=$true, 32 | ParameterSetName='NamePrefix')] 33 | [string] 34 | $SubVsFilter, 35 | 36 | [Parameter(Mandatory=$true)] 37 | [ipaddress] 38 | $RealServer, 39 | 40 | [Parameter(Mandatory=$true)] 41 | [ValidateRange(1,65535)] 42 | [int] 43 | $Port, 44 | 45 | [Parameter(Mandatory=$false)] 46 | [ValidateRange(1,65535)] 47 | [int] 48 | $Weight=1000 49 | ) 50 | 51 | if ($PSCmdlet.ParameterSetName -eq "Index") { Write-Verbose "VS from Pipeline, Index $Index" 52 | if ($pscmdlet.ShouldProcess("VS $Index", "Add RS $RealServer`:$Port")) { 53 | Send-LBMessage -command addrs -ParameterValuePair @{"vs"=$Index ; "rs"=$RealServer; "rsport"=$Port; "weight"=$Weight } 54 | } } else { 55 | Write-Verbose "Getting VS from Filter $SubVsFilter" 56 | $subVSGroup = Get-VirtualService | Where-Object {$_.nickname -like $SubVsFilter -and $_.mastervs -eq 0 -and (-not$_.subvs)} 57 | foreach ($subVs in $subVSGroup) { 58 | if ($pscmdlet.ShouldProcess($subVs.nickname, "Add RS $RealServer`:$Port")) { 59 | Send-LBMessage -command addrs -ParameterValuePair @{"vs"=$subVs.Index ; "rs"=$RealServer; "rsport"=$Port; "weight"=$Weight } 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /AudioCodesCdr.ps1: -------------------------------------------------------------------------------- 1 | 2 | function Get-Cdr { 3 | [cmdletbinding()] 4 | param( 5 | [Parameter(Mandatory,ValueFromPipeline)] 6 | [System.IO.FileInfo] 7 | $Path, 8 | [Parameter(Mandatory)] 9 | [ValidateSet("MEDIA","SBC")] 10 | [string]$Type 11 | ) 12 | process { 13 | $Pattern = "\|CALL_[START|CONNECT|END]" 14 | if($type -eq "MEDIA") { 15 | $Pattern = "\|MEDIA_[START|UPDATE|END]" 16 | } 17 | if(Test-Path $Path) { 18 | Write-Verbose "Get CDR from: $Path" 19 | (Select-String -Pattern $Pattern -Path $Path | Select-Object -ExpandProperty line).TrimEnd() -replace "\|","," -replace "\s*,","," -replace "BYE(.*)","BYE" -replace "CANCEL(.*)","CANCEL" -replace "q.850(.*)","Q.850" 20 | } 21 | } 22 | } 23 | 24 | function Split-Cdr { 25 | [CmdletBinding()] 26 | param( 27 | [Parameter(Mandatory,ValueFromPipeline)] 28 | [System.IO.FileInfo] 29 | $Path, 30 | [System.IO.FileInfo] 31 | $OutputFolder = $env:temp 32 | ) 33 | # create output folder if it does not exist 34 | New-Item -Path $OutputFolder -ItemType Directory -ErrorAction SilentlyContinue 35 | $MediaPath = Join-path -Path $OutputFolder -ChildPath media.txt 36 | $SBCPath = Join-path -Path $OutputFolder -ChildPath sbc.txt 37 | # delete existing target files if they exist 38 | Remove-Item $MediaPath,$SBCPath -ErrorAction SilentlyContinue 39 | foreach($f in $path) { 40 | Get-Cdr -Path $f -Type SBC | Add-Content $SBCPath 41 | Get-Cdr -Path $f -Type MEDIA | Add-Content $MediaPath 42 | } 43 | } 44 | 45 | function Import-Cdr { 46 | <# 47 | .SYNOPSIS 48 | Import CDR from file. 49 | .DESCRIPTION 50 | This function uses Import-Csv to import CDR information form a file. 51 | .EXAMPLE 52 | PS C:\> Import-Cdr -Path .\CDR-2018-10-03-08.log -Header $Header 53 | This example imports Media CDRs. 54 | .INPUTS 55 | [system.io.fileinfo] 56 | .OUTPUTS 57 | [psobject] 58 | .NOTES 59 | Author: @torggler 60 | #> 61 | [CmdletBinding()] 62 | param( 63 | [Parameter(Mandatory,ValueFromPipeline)] 64 | [System.IO.FileInfo] 65 | $Path, 66 | [Parameter()] 67 | [string[]]$Header 68 | ) 69 | process { 70 | if(Test-Path $Path) { 71 | Import-Csv -Path $Path -Delimiter "," -Header $Header | Select-Object *,@{n="Jitter";e={$_.RTPjitter -as [int]}},@{n="Delay";e={$_.RTPdelay -as [int]}} -ExcludeProperty RTPjitter,RTPdelay 72 | } 73 | } 74 | } 75 | 76 | 77 | function Get-CdrTitle { 78 | <# 79 | .SYNOPSIS 80 | Extract CSV header from CDR file. 81 | .DESCRIPTION 82 | This function extracts the header information from a CDR file. This can later be used, to import the CDR using Import-Csv. 83 | .EXAMPLE 84 | PS C:\> Get-CdrTitle .\CDR-2018-10-03-08.log -Type SBC 85 | This example extracts the header for SBCReport. 86 | .EXAMPLE 87 | PS C:\> Get-CdrTitle .\CDR-2018-10-03-08.log -Type MEDIA 88 | This example extracts the header for MediaReport. 89 | .INPUTS 90 | [system.io.fileinfo] 91 | .OUTPUTS 92 | [string] 93 | .NOTES 94 | Author: @torggler 95 | #> 96 | [CmdletBinding()] 97 | param( 98 | [Parameter(Mandatory,ValueFromPipeline)] 99 | [System.IO.FileInfo] 100 | $Path, 101 | [Parameter(Mandatory)] 102 | [ValidateSet("MEDIA","SBC","GW")] 103 | [string]$Type 104 | ) 105 | switch ($type) { 106 | 'media' { $Pattern = "MediaReportType" } 107 | 'gw' { $Pattern = "GWReportType" } 108 | 'sbc' { $Pattern = "SBCReportType" } 109 | } 110 | 111 | if(Test-Path $Path) { 112 | #$title = Select-String -Path $path -Pattern $Pattern | Select-Object -ExpandProperty line | Select-Object -First 1 113 | #$out = $title -replace "^.*?\|","Timestamp|" -replace " ","" -split "\|" -replace "\(\w+\)","" -replace $Pattern,"ReportType" 114 | } 115 | if($Type -eq "MEDIA" -and -not($out)){ 116 | $out = @('Timestamp','ReportType','SIPCallId','SessionId','Cid','MediaType','Coder','Intrv','LocalRtpIp','LocalRtpPort','RemoteRtpIp','RemoteRtpPort','InPackets','OutPackets','LocalPackLoss','RemotePackLoss','RTPdelay','RTPjitter','TxRTPssrc','RxRTPssrc','LocalRFactor','RemoteRFactor','LocalMosCQ','RemoteMosCQ','TxRTPIPDiffServ','LatchedRtpIp','LatchedRtpPort','LatchedT38Ip','LatchedT38Port','CoderTranscoding','LegId') 117 | } elseif($Type -eq "SBC" -and -not($out)) { 118 | $out = @('Timestamp','ReportType','EPTyp','SIPCallId','SessionId','Orig','SourceIp','SourcePort','DestIp','DestPort','TransportType','SrcURI','SrcURIBeforeMap','DstURI','DstURIBeforeMap','Durat','TrmSd','TrmReason','TrmReasonCategory','SetupTime','ConnectTime','ReleaseTime','RedirectReason','RedirectURINum','RedirectURINumBeforeMap','TxSigIPDiffServ','IPGroup','SrdId','SIPInterfaceId','ProxySetId','IpProfileId','MediaRealmId','DirectMedia','SIPTrmReason','SipTermDesc') 119 | } elseif ($Type -eq "GW" -and -not($out)) { 120 | $out = @('Timestamp','ReportType','Cid','SessionId','LegId','Trunk','BChan','ConId','TG','EPTyp','Orig','SourceIp','DestIp','SrcTON','SrcNPI','SrcPhoneNum','SrcNumBeforeMap','DstTON','DstNPI','DstPhoneNum','DstNumBeforeMap','Duration','Coder','Intrv','RtpIp','Port','TrmSd','TrmReason','Fax','InPackets','OutPackets','PackLoss','RemotePackLoss','SIPCallId','SetupTime','ConnectTime','ReleaseTime','RTPdelay','RTPjitter','RTPssrc','RemoteRTPssrc','RedirectReason','TON','NPI','RedirectPhonNum','MeteringPulses','SrcHost','SrcHostBeforeMap','DstHost','DstHostBeforeMap','IPG (name)','LocalRtpIp','LocalRtpPort','Amount','Mult','TrmReasonCategory','RedirectNumBeforeMap','SrdId (name)','SIPInterfaceId (name)','ProxySetId (name)','IpProfileId (name)','MediaRealmId (name)','SigTransportType','TxRTPIPDiffServ','TxSigIPDiffServ','LocalRFactor','RemoteRFactor','LocalMosCQ','RemoteMosCQ','SigSourcePort','SigDestPort','MediaType','AMD','Percent','SIPTrmReason','SIPTer') 121 | } 122 | Write-Output $out 123 | } 124 | 125 | 126 | <# 127 | function Get-BadStream { 128 | [CmdletBinding()] 129 | param ( 130 | [Parameter(Mandatory)] 131 | [System.IO.FileInfo] 132 | $Path, 133 | [Parameter()] 134 | [ValidateSet("Jitter","Delay","PackLoss")] 135 | $Type = "Jitter", 136 | [int] 137 | $Count 138 | ) 139 | process { 140 | switch($Type){ 141 | 'Jitter' { $fs = {$_.RTPjitter -gt 1} } 142 | 'Delay' { $fs = {$_.RTPdelay -gt 1} } 143 | 'PackLoss' { $fs = {$_.RemotePackLoss -gt 1 -or $_.LocalPackLoss -gt 1}} 144 | } 145 | if($count) { 146 | ### Add Header! 147 | Import-Cdr -Path $Path | Where-Object -FilterScript $fs | Select-Object -First $Count 148 | } else { 149 | Import-Cdr -Path $Path | Where-Object -FilterScript $fs 150 | } 151 | 152 | } 153 | } 154 | #> 155 | 156 | function Get-NrFromUri { 157 | [CmdletBinding()] 158 | param ( 159 | [Parameter(Mandatory,ValueFromPipeline)] 160 | $InputObject 161 | ) 162 | process { 163 | foreach($i in $InputObject) { 164 | $i -replace "[@|;].*$","" 165 | } 166 | } 167 | } 168 | 169 | function Get-DateFromTime { 170 | [CmdletBinding()] 171 | param ( 172 | [Parameter(Mandatory,ValueFromPipeline)] 173 | $InputObject 174 | ) 175 | process { 176 | foreach($i in $InputObject) { 177 | $J = $i -split "UTC" 178 | Get-Date (($J[1] -replace "(\w{3})(\w{3})(\d{2})(\d{4})","`$1 `$2 `$3 `$4"),$J[0] -join " ") 179 | } 180 | } 181 | } 182 | 183 | function Get-HostFromPath { 184 | [CmdletBinding()] 185 | param ( 186 | [Parameter(Mandatory,ValueFromPipeline)] 187 | [System.IO.FileInfo] 188 | $InputObject 189 | ) 190 | process { 191 | # split the Path at \ and try to cast each part as [ipaddress]. Only returns valid casts. 192 | $InputObject.DirectoryName -split "\\" | ForEach-Object { $_ -as [ipaddress] } | Select-Object -ExpandProperty IPAddressToString 193 | } 194 | } 195 | 196 | function Get-MediaCdr { 197 | [cmdletbinding()] 198 | param($path) 199 | $header = Get-CdrTitle -Path $path -Type MEDIA 200 | $tempfile = Join-path -Path $env:temp -ChildPath "$((get-date).ticks).txt" 201 | Get-Cdr $path -Type MEDIA | Set-Content $tempfile 202 | Import-Cdr -Header $header -Path $tempfile 203 | } 204 | 205 | function Get-SbcCdr { 206 | [cmdletbinding()] 207 | param($path) 208 | $header = Get-CdrTitle -Path $path -Type SBC 209 | $tempfile = Join-path -Path $env:temp -ChildPath "$((get-date).ticks).txt" 210 | Get-Cdr $path -Type SBC | Set-Content $tempfile 211 | Import-Cdr -Header $header -Path $tempfile 212 | } 213 | 214 | function Get-GWCdr { 215 | [cmdletbinding()] 216 | param($path) 217 | $header = Get-CdrTitle -Path $path -Type gw 218 | $tempfile = Join-path -Path $env:temp -ChildPath "$((get-date).ticks).txt" 219 | Get-Cdr $path -Type sbc | Set-Content $tempfile 220 | Import-Cdr -Header $header -Path $tempfile 221 | } 222 | -------------------------------------------------------------------------------- /AudioCodesIPPhone.ps1: -------------------------------------------------------------------------------- 1 | 2 | function Get-IPPCfg { 3 | <# 4 | .SYNOPSIS 5 | Get phone cfg from AudioCodes IP Phone Manager (Express). 6 | .DESCRIPTION 7 | This function uses Invoke-WebRequest to retreive configuration information from an AudioCodes IP Phone Manager. 8 | .EXAMPLE 9 | PS C:\> Get-IPPCfg -ComputerName acipp01.uclab.eu -Phone 450HD -Tenant uclab_de 10 | This example gets the config template file for 450HD phones in the uclab_de tenant. 11 | .INPUTS 12 | None. 13 | .OUTPUTS 14 | [psobject] 15 | .NOTES 16 | Author: @torggler 17 | #> 18 | [CmdletBinding()] 19 | param( 20 | # FQDN of the IP Phone Manager 21 | [Parameter(Mandatory)] 22 | [string]$ComputerName, 23 | # IP Phone Type 24 | [Parameter(Mandatory)] 25 | [ValidateSet("450HD","445HD","440HD","420HD")] 26 | [string]$Phone, 27 | # MAC Address of an IP Phone to get a specific config file 28 | [Parameter()] 29 | [string]$MacAddress = "00065BBC7AC7", 30 | # Tenant Name as configured on IP Phone Manager 31 | [Parameter()] 32 | [string]$Tenant = "Default" 33 | ) 34 | $uri = "http://{0}/ipp/tenant/{1}/{2}.cfg" -f $ComputerName,$Tenant,$MacAddress 35 | $ua = "AUDC-IPPhone-{0}_UC_0.0.0.0/0" -f $Phone 36 | $result = Invoke-WebRequest -Uri $uri -UserAgent $ua 37 | New-Object -TypeName psobject -Property ([ordered]@{ 38 | TemplateName = $result.headers["X-Template-Name"] 39 | Content = ConvertFrom-ByteArray($result.content) 40 | }) 41 | 42 | } 43 | function ConvertFrom-ByteArray($i) { 44 | $enc = [System.Text.Encoding]::ASCII 45 | $enc.GetString($i) 46 | } 47 | 48 | 49 | 50 | function Set-DhcpProvServ { 51 | <# 52 | .SYNOPSIS 53 | Set DHCP Option 160 (provisioning server) for a scope on one or more DHCP servers. 54 | .DESCRIPTION 55 | This function can be used to set the Provisioning Server DHCP Option (160) 56 | .EXAMPLE 57 | PS C:\> Set-DhcpProvServ -ComputerName "dhcp01.example.com" -ScopeId "192.168.1.0" -Uri "http://192.168.1.10/firmwarefiles;ipp/tenant/uclab_de" 58 | 59 | This example sets the provisioning server option for scope 192.168.1.0 on server dhcp01. 60 | .EXAMPLE 61 | PS C:\> $c = New-CimSession -ComputerName "dhcp01.example.com","dhcp02.example.com" 62 | PS C:\> Get-DhcpServerv4Scope -ScopeId 192.168.1.0,192.168.2.0 -CimSession $c | Set-DhcpProvServ -Uri "http://192.168.1.10/firmwarefiles;ipp/tenant/uclab_de" -PassThru 63 | 64 | OptionId Name Type Value VendorClass UserClass PolicyName 65 | -------- ---- ---- ----- ----------- --------- ---------- 66 | 160 Provisioning... String {http://192.168.1... 67 | 160 Provisioning... String {http://192.168.1... 68 | 160 Provisioning... String {http://192.168.1... 69 | 160 Provisioning... String {http://192.168.1... 70 | 71 | In this example, we create a new CIM session to two remote DHCP Servers and then we use Get-DhcpServerv4Scope to retrieve two scopes from each Server. 72 | We use the scopes as input for the Set-DhcpProvServ function and set the Option 160 to the same URI on all scopes. 73 | 74 | .INPUTS 75 | [Microsoft.Management.Infrastructure.CimInstance] 76 | .OUTPUTS 77 | None. 78 | .NOTES 79 | Author: @torggler 80 | #> 81 | [CmdletBinding( 82 | SupportsShouldProcess=$true, 83 | DefaultParameterSetName="ByComputerName" 84 | )] 85 | param( 86 | [Parameter(Mandatory,ParameterSetName="ByComputerName")] 87 | [string[]] 88 | $ComputerName, 89 | [Parameter(ParameterSetName="ByObject",ValueFromPipeline=$true)] 90 | [Microsoft.Management.Infrastructure.CimInstance] 91 | $InputObject, 92 | [Parameter()] 93 | [System.Net.IPAddress[]] 94 | $ScopeId, 95 | [Parameter(Mandatory)] 96 | [string] 97 | $Uri, 98 | [Parameter()] 99 | [switch] 100 | $PassThru 101 | ) 102 | process { 103 | if($InputObject) { 104 | Write-Verbose "Information by input object" 105 | $ComputerName = $InputObject.PSComputerName 106 | $ScopeId = $InputObject.ScopeId 107 | } 108 | foreach ($dhcpSrv in $ComputerName) { 109 | Write-Verbose "DHCP Server is $dhcpSrv" 110 | foreach ($scope in $ScopeId) { 111 | Write-Verbose "ScopeId is $scope" 112 | if ($pscmdlet.ShouldProcess("$dhcpSrv\$scope", "Set Option 160 to $Uri")) { 113 | Set-DhcpServerv4OptionValue -ScopeId $scope -OptionId 160 -Value $Uri -ComputerName $dhcpSrv -PassThru:$PassThru 114 | } 115 | } 116 | } 117 | } 118 | } 119 | 120 | 121 | 122 | function Get-DhcpProvServ { 123 | <# 124 | .SYNOPSIS 125 | Get DHCP Option 160 (provisioning server) for a scope from one or more DHCP servers. 126 | .DESCRIPTION 127 | This function can be used to get the Provisioning Server DHCP Option (160). 128 | .EXAMPLE 129 | PS C:\> Get-DhcpProvServ -ComputerName "dhcp01.example.com" -ScopeId "192.168.1.0" 130 | 131 | This example gets the provisioning server option for scope 192.168.1.0 from server dhcp01. 132 | .EXAMPLE 133 | PS C:\> $c = New-CimSession -ComputerName "dhcp01.example.com","dhcp02.example.com" 134 | PS C:\> Get-DhcpServerv4Scope -ScopeId 192.168.1.0,192.168.2.0 -CimSession $c | Get-DhcpProvServ 135 | 136 | In this example, we create a new CIM session to two remote DHCP Servers and then we use Get-DhcpServerv4Scope to retrieve two scopes from each Server. 137 | We use the scopes as input for the Get-DhcpProvServ function and get configured value for each scope. 138 | 139 | .INPUTS 140 | [Microsoft.Management.Infrastructure.CimInstance] 141 | .OUTPUTS 142 | [psobject] 143 | .NOTES 144 | Author: @torggler 145 | #> 146 | [CmdletBinding(DefaultParameterSetName="ByComputerName")] 147 | param( 148 | [Parameter(ParameterSetName="ByComputerName")] 149 | [string[]] 150 | $ComputerName, 151 | [Parameter(ParameterSetName="ByObject",ValueFromPipeline=$true)] 152 | [Microsoft.Management.Infrastructure.CimInstance] 153 | $InputObject, 154 | [Parameter()] 155 | [System.Net.IPAddress[]] 156 | $ScopeId, 157 | [Parameter()] 158 | [int] 159 | $optionId = 160 160 | ) 161 | process { 162 | if($InputObject) { 163 | $ComputerName = $InputObject.PSComputerName 164 | $ScopeId = $InputObject.ScopeId 165 | } 166 | foreach ($s in $ComputerName) { 167 | Write-Verbose "Server is $s" 168 | foreach($scope in $ScopeId){ 169 | Write-Verbose "Scope is $scope" 170 | $o = Get-DhcpServerv4OptionValue -ScopeId $scope -OptionId $optionId -ComputerName $s -ErrorAction SilentlyContinue 171 | New-Object -TypeName psobject -Property ([ordered]@{ 172 | DhcpServer = $s 173 | Scopde = $scope 174 | ProvisioningServer = $o.Value 175 | }) 176 | } 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /Compare-FileHash.ps1: -------------------------------------------------------------------------------- 1 | 2 | 3 | function Compare-FileHash { 4 | [CmdletBinding()] 5 | param ( 6 | [ValidateScript({Test-Path $_ -PathType Container})] 7 | $Source, 8 | [ValidateScript({Test-Path $_ -PathType Container})] 9 | $Destination 10 | ) 11 | 12 | try { 13 | $sourceFiles = Get-ChildItem -Path $Source -Recurse -File -ErrorAction Stop 14 | $destinationFiles = Get-ChildItem -Path $Destination -Recurse -File -ErrorAction Stop 15 | } catch { 16 | Write-Warning "Could not get files: $_" 17 | break 18 | } 19 | $outArr = @() 20 | foreach($file in $sourceFiles) { 21 | $h1 = Get-FileHash -Path $file.FullName 22 | 23 | if ($destinationFiles.Where{$_.Name -eq $file.Name}) { 24 | $h2 = Get-FileHash -Path $destinationFiles.Where{$_.Name -eq $file.Name}.FullName 25 | 26 | if($h1.Hash -eq $h2.Hash) { 27 | Write-Verbose "$($file.FullName) matches $($h2.path)" 28 | } else { 29 | $out = @{ 30 | SourceFile = $h1.Path; 31 | SourceFileHash = $h1.Hash; 32 | DestinationFile = $h2.Path; 33 | DestinationFileHash = $h2.Hash; 34 | } 35 | Write-Output (New-Object -TypeName psobject -Property $out) 36 | } 37 | } else { 38 | Write-Verbose "Could not fild file $($file.Name) in $Destination" 39 | 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /CryptoTools.ps1: -------------------------------------------------------------------------------- 1 | function Convert-BchAddress { 2 | <# 3 | .SYNOPSIS 4 | Converts Bitcoin Cash Address formats. 5 | .DESCRIPTION 6 | This function uses https://cashaddr.bitcoincash.org to convert Bitcoin Cash address formats. It supports legacy and bitcoincash: address formats. 7 | The outout is a custom object containing all address formats and links to block explorers to for convenience. 8 | .EXAMPLE 9 | PS C:\> Convert-BchAddress -Address "1BppmEwfuWCB3mbGqah2YuQZEZQGK3MfWc" 10 | 11 | This example converts a legacy address to the new bitcoincash format. 12 | .EXAMPLE 13 | PS C:\> Convert-BchAddress -Address "bitcoincash:qpmtetdtqpy5yhflnmmv8s35gkqfdnfdtywdqvue4p" 14 | 15 | This example converts a new address to the legacy format. 16 | .INPUTS 17 | [string] 18 | .OUTPUTS 19 | [PSCustomObject] 20 | .NOTES 21 | More information: https://www.bitcoinabc.org/cashaddr 22 | #> 23 | [CmdletBinding()] 24 | param( 25 | [Parameter(ValueFromPipeline=$true, 26 | ValueFromPipelineByPropertyName=$true)] 27 | [ValidateNotNullOrEmpty()] 28 | $Address 29 | ) 30 | $uri = "https://cashaddr.bitcoincash.org/convert?address=$Address" 31 | try { 32 | $out = Invoke-RestMethod -Uri $uri -ErrorAction Stop 33 | } catch { 34 | Write-Warning "Could not connect." 35 | } 36 | $out | Add-Member -MemberType NoteProperty -Name "Blockchair" -Value "https://blockchair.com/bitcoin-cash/address/$($out.cashaddr.replace(":","%3A"))" 37 | $out | Add-Member -MemberType NoteProperty -Name "Blockdozer" -Value "https://blockdozer.com/address/$($out.cashaddr.replace(":","%3A"))" 38 | Write-Output $out 39 | } 40 | 41 | enum CryptoCurrencySymbol { 42 | eth 43 | btc 44 | ltc 45 | bch 46 | } 47 | 48 | class CryptoCurrency { 49 | [string]$address 50 | } 51 | 52 | class ETH : CryptoCurrency { 53 | ETH ($obj) { 54 | $this.address = $obj.address 55 | $this.balance = $obj.balance / 1000000000000000000 56 | $this.sent = $obj.total_sent / 1000000000000000000 57 | $this.received = $obj.total_received / 1000000000000000000 58 | } 59 | [double]$balance 60 | [double]$sent 61 | [double]$received 62 | } 63 | 64 | class BTC : CryptoCurrency { 65 | BTC ($obj) { 66 | $this.address = $obj.address 67 | $this.balance = $obj.balance / 100000000 68 | $this.sent = $obj.total_sent / 100000000 69 | $this.received = $obj.total_received / 100000000 70 | } 71 | [double]$balance 72 | [double]$sent 73 | [double]$received 74 | } 75 | function Get-BlockCypherAddress { 76 | [CmdletBinding()] 77 | param( 78 | [Parameter( 79 | Mandatory=$true, 80 | Position=0 81 | )] 82 | [string] 83 | $Address, 84 | [string] 85 | $Version = "v1" 86 | ) 87 | $Currency = Get-CurrencyFromAddress -Address $Address 88 | $Address = $Address.Replace("0x","") 89 | Write-Verbose "Currency is $Currency" 90 | Invoke-RestMethod https://api.blockcypher.com/$version/$currency/main/addrs/$Address 91 | } 92 | 93 | function Get-BlockCypherBalance { 94 | [CmdletBinding()] 95 | param( 96 | [Parameter( 97 | Mandatory=$true, 98 | Position=0 99 | )] 100 | [string] 101 | $Address, 102 | [string] 103 | $Version = "v1" 104 | ) 105 | $Currency = Get-CurrencyFromAddress -Address $Address 106 | $Address = $Address.Replace("0x","") 107 | Write-Verbose "Currency is $Currency" 108 | $r = Invoke-RestMethod https://api.blockcypher.com/$version/$currency/main/addrs/$Address/balance 109 | if ($r) { 110 | switch($Currency) { 111 | "eth" { 112 | [ETH]::new($r) 113 | } 114 | Default { 115 | [BTC]::new($r) 116 | } 117 | } 118 | } 119 | } 120 | 121 | function Get-BlockCypherTransaction { 122 | [CmdletBinding(DefaultParameterSetName="ByTxHash")] 123 | param( 124 | [Parameter( 125 | Position=0, 126 | ParameterSetName="ByTxHash", 127 | Mandatory=$True 128 | )] 129 | [string] 130 | $Hash, 131 | [Parameter( 132 | ParameterSetName="ByAddress", 133 | Mandatory=$True 134 | )] 135 | [string] 136 | $Address, 137 | [string] 138 | $Version = "v1", 139 | [Parameter(ParameterSetName="ByTxHash")] 140 | [CryptoCurrencySymbol] 141 | $Currency = "eth" 142 | ) 143 | 144 | # provide two possibilites of using the function, 145 | # either get a specific tx by hash or get all tx for a certain address 146 | 147 | if($Hash) { 148 | $hash = $hash.Replace("^0x","") 149 | Invoke-RestMethod https://api.blockcypher.com/$version/$currency/main/txs/$Hash 150 | } elseif ($Address) { 151 | Get-BlockCypherAddress -Address $Address | Select-Object -ExpandProperty txrefs 152 | } 153 | } 154 | 155 | function Get-CurrencyFromAddress { 156 | [CmdletBinding()] 157 | param($Address) 158 | switch ($Address) { 159 | { $_ -match "^[13][a-zA-Z0-9]{27,34}$" } { "btc" } 160 | { $_ -match "^L[a-km-zA-HJ-NP-Z1-9]{26,33}$" } { "ltc" } 161 | { $_ -match "^(0x)?[0-9a-f]{40}$" } { "eth" } 162 | } 163 | } 164 | 165 | 166 | function Get-BchBalance { 167 | [CmdletBinding()] 168 | param( 169 | $Address 170 | ) 171 | 172 | $result = Invoke-RestMethod "https://api.blockchair.com/bitcoin-cash/dashboards/address/$address" 173 | if($result){ 174 | $result.data 175 | } 176 | 177 | } 178 | 179 | function Get-BchTransaction { 180 | [CmdletBinding()] 181 | param( 182 | $Hash 183 | ) 184 | $result = Invoke-RestMethod "https://api.blockchair.com/bitcoin-cash/transactions?q=hash($hash)" 185 | if($result){ 186 | $result.data 187 | } 188 | } 189 | 190 | 191 | #https://explorer.bitcoin.com/api/btc/addr/14hbuMuFCGSCzQr3TCVqPUKGkDGbepEoe2 192 | #https://explorer.bitcoin.com/api/bch/txs/?address=14hbuMuFCGSCzQr3TCVqPUKGkDGbepEoe2 193 | #https://explorer.bitcoin.com/api/bch/txs/?hash=ffe712907e11479bdca14445f66b5fbabd4a5e2c73bc7d7f1511429a470be036 194 | 195 | 196 | function Get-ChainfeedTx { 197 | [CmdletBinding()] 198 | param ( 199 | [string] 200 | $Hash 201 | ) 202 | process { 203 | $Response = Invoke-RestMethod https://chainfeed.org/tx/$Hash 204 | New-Object -TypeName psobject -Property (@{ 205 | Sender = $Response.Sender 206 | Text = [System.Text.Encoding]::ASCII.GetString($Response.data[-1].buf.data) 207 | }) 208 | } 209 | } 210 | 211 | 212 | 213 | function get-unixtime { 214 | param([datetime]$date) 215 | if(-not $date) { 216 | $date = ([datetime]::UtcNow).AddHours(-1) 217 | } 218 | $ts = New-TimeSpan -Start (Get-Date 01.01.1970) -End $date 219 | [int]$ts.TotalSeconds 220 | } 221 | function invoke-whalealertapi { 222 | param( 223 | $endpoint = "status", 224 | $apikey = $whalealertapi, 225 | $baseUrl = "https://api.whale-alert.io/v1", 226 | $currency, 227 | $minvalue, 228 | $start = (get-unixtime) 229 | ) 230 | $header = @{ 231 | "X-WA-API-KEY" = $apikey 232 | } 233 | $uri = $baseUrl,$endpoint -join "/" 234 | $uri += "?start=$start" 235 | if($currency){ 236 | $uri += "¤cy=$currency" 237 | } 238 | if($minvalue){ 239 | $uri += "&min_value=$minvalue" 240 | } 241 | $r = Invoke-RestMethod -Uri $uri -Headers $header 242 | $r.transactions 243 | } 244 | function convertto-ether { 245 | param($i) 246 | $i/1000000000000000000 247 | } 248 | 249 | function invoke-etherscanio { 250 | param( 251 | [Parameter()] 252 | [ValidateSet("mainnet","goerli","rinkeby")] 253 | $network = "mainnet", 254 | [Parameter()] 255 | [ValidateSet("account","transaction")] 256 | $module = "account", 257 | $apikey = $etherscanapi 258 | ) 259 | if($network -eq "mainnet"){$url = ""} else {$url = "-$network"} 260 | $baseUrl = "https://api{0}.etherscan.io/api?module={1}" -f $url,$module 261 | 262 | if($address){ 263 | $baseUrl += "&action=balance&address=$address" 264 | } 265 | 266 | $baseUrl += "&apikey=$apikey" 267 | 268 | $r = Invoke-RestMethod -Uri $baseUrl 269 | $r 270 | } 271 | 272 | function Get-EtherScanBalance { 273 | param( 274 | $Address, 275 | $apikey = "N9XZ94DDT1NBD18PJ8DZKXU76ZUNDVRQ83" 276 | ) 277 | $out=invoke-etherscanio -address $Address 278 | convertto-ether -i $out.result 279 | } -------------------------------------------------------------------------------- /ExDagMaintenance/ExDagMaintenance.psm1: -------------------------------------------------------------------------------- 1 | ### 2 | # This is based on the following scripts by Justin Beeden 3 | # I made some adjustments for myself and merged the functions into a Module. 4 | # This is a work in progress and not yet fit for production use. 5 | # https://gallery.technet.microsoft.com/office/Exchange-2013-DAG-3ac89826 6 | ### 7 | 8 | function Start-ExDagMaintenance { 9 | <# 10 | .NOTES 11 | Written by Justin Beeden 12 | V2.1 2016-09-16 13 | 2.1 @torggler: Added -StopTransport switch to stop transport services. 14 | 2.0 Added logic to confirm DAG File Share Witness is operational to maintain quorum 15 | Added logic to confirm QueueTargetFQDN is a FQDN, will attempt to resolve to FQDN if hostname is entered 16 | Added logic to confirm mail queues have been moved to QueueTargetFQDN 17 | Added logic to confirm all active database copies have been moved to another DAG member 18 | 1.1 Corrected Spelling error in one of the parameters 19 | 1.0 Initial 20 | .SYNOPSIS 21 | Puts Exchange 2013 DAG nodes into maintenance mode. 22 | .DESCRIPTION 23 | Puts Exchange 2013 DAG nodes into maintenance mode. 24 | http://technet.microsoft.com/en-us/library/dd298065%28v=exchg.150%29.aspx#Pm 25 | .PARAMETER Server 26 | Specifies the DAG node Server name to be put into maintenance mode. 27 | .PARAMETER QueueTargetFQDN 28 | Specifies the target Exchange 2013 mailbox server FQDN to move the mail queue to from the Server to be put into maintenance mode. 29 | .PARAMETER StopTransport 30 | Stops the MSExchangeFrontendTransport and MSExchangeTransport services. 31 | .EXAMPLE 32 | PS> .\Start2013DagServerMaintenance.ps1 -Server Server1 -QueueTargetFQDN Server2.contoso.com 33 | Puts Server1 into maintenace mode and moves all queued mail to Server2 for delivery 34 | .EXAMPLE 35 | PS> .\Start2013DagServerMaintenance.ps1 -Server Server1 -QueueTargetFQDN Server2.contoso.com -StopTransport 36 | Puts Server1 into maintenace mode, moves all queued mail to Server2 for delivery and stops transport service on Server1 37 | #> 38 | 39 | #Requires -version 3.0 40 | 41 | [CmdletBinding()] 42 | Param( 43 | [Parameter(Position=0, Mandatory = $true, 44 | HelpMessage="Enter the name of the DAG Server to put into Maintenance mode.")] 45 | [string]$Server, 46 | 47 | [Parameter(Position=1, Mandatory = $true, 48 | HelpMessage="Enter FQDN of server to move mail queue to.")] 49 | [string]$QueueTargetFQDN, 50 | 51 | # Stop Transport Services 52 | [Parameter(Position=2, Mandatory = $false)] 53 | [switch]$StopTransport 54 | ) 55 | Begin 56 | { 57 | try { 58 | #If QueueTargetFQDN is not enterend as a FQDN will attempt to resolve it to a FQDN 59 | $TargetServer = ([System.Net.Dns]::GetHostByName($QueueTargetFQDN)).Hostname 60 | } 61 | catch { 62 | #If above does not resolve to a valid FQDN script will throw error and quit script 63 | Throw "Could not resolve ServerFQDN: $QueueTargetFQDN hostname needs to be resolvable FQDN." 64 | } 65 | } 66 | Process 67 | { 68 | ### Moved out creation of supporting functions. Rename! 69 | 70 | Write-Verbose "Checking DAG File Share Witness" 71 | CheckFSW 72 | 73 | Write-Verbose "Begining the process of draining the transport queues" 74 | Set-ServerComponentState $Server -Component HubTransport -State Draining -Requester Maintenance 75 | 76 | Write-verbose "Begining the process of draining all Unified Messaging calls" 77 | Set-ServerComponentState $Server -Component UMCallRouter –State Draining –Requester Maintenance 78 | 79 | Write-Verbose "Redirecting messages pending delivery in the local queues to $QueueTargetFQDN" 80 | Redirect-Message -Server $Server -Target $TargetServer -Confirm:$false 81 | 82 | Write-Verbose "Pausing the cluster node, which prevents the node from being and becoming the PrimaryActiveManager" 83 | Suspend-ClusterNode $Server 84 | 85 | Write-Verbose "Moving all active databases currently hosted on $Server to other DAG members" 86 | Set-MailboxServer $Server -DatabaseCopyActivationDisabledAndMoveNow $True 87 | 88 | Write-Verbose "Preventing $Server from hosting active database copies" 89 | Set-MailboxServer $Server -DatabaseCopyAutoActivationPolicy Blocked 90 | 91 | Write-Verbose "Placing $Server into maintenance mode" 92 | Set-ServerComponentState $Server -Component ServerWideOffline -State Inactive -Requester Maintenance 93 | } 94 | End 95 | { 96 | CheckQueues 97 | 98 | CheckActiveDatabase 99 | 100 | Write-Host "$Server is fully in maintenance mode and ready for maintenance." -ForegroundColor Green 101 | } 102 | } 103 | 104 | function Stop-ExDagMaintenance { 105 | 106 | <# 107 | .NOTES 108 | Written by Justin Beeden 109 | V1.2 11.16.2013 110 | .SYNOPSIS 111 | Removes Exchange 2013 DAG nodes out of maintenance mode. 112 | .DESCRIPTION 113 | Removes Exchange 2013 DAG nodes out of maintenance mode. 114 | http://technet.microsoft.com/en-us/library/dd298065%28v=exchg.150%29.aspx#Pm 115 | .PARAMETER Server 116 | Specifies the DAG node Server name to be removed from maintenance mode. 117 | .EXAMPLE 118 | PS> .\Stop2013DagServerMaintenance.ps1 -Server Server1 119 | #> 120 | 121 | #Requires -version 3.0 122 | 123 | [CmdletBinding()] 124 | Param( 125 | [Parameter(Mandatory = $true, 126 | HelpMessage="Enter the name of DAG Server to remove from Maintenance mode.")] 127 | [string]$Server 128 | ) 129 | 130 | #Designates that the server is out of maintenance mode 131 | Write-Verbose "Taking $Server out of maintenance mode" 132 | Set-ServerComponentState $Server -Component ServerWideOffline -State Active -Requester Maintenance 133 | 134 | #Allows the server to accept Unified Messaging calls 135 | Write-Verbose "$Server can now accept Unified Messaging calls." 136 | Set-ServerComponentState $Server -Component UMCallRouter –State Active –Requester Maintenance 137 | 138 | #Resumes the node in the cluster and enables full cluster functionality for the server 139 | Write-Verbose "Resuming the cluster node and enabling full cluster functionality." 140 | Resume-ClusterNode $Server 141 | 142 | #Allows databases to become active on the server 143 | Write-Verbose "$Server can now host active database copies." 144 | Set-MailboxServer $Server -DatabaseCopyActivationDisabledAndMoveNow $False 145 | 146 | #Removes the automatic activation blocks 147 | Write-Verbose "$Server can now automatically host active database copies." 148 | Set-MailboxServer $Server -DatabaseCopyAutoActivationPolicy Unrestricted 149 | 150 | #Resumes the transport queues and allows the server to accept and process messages 151 | Write-Verbose "Transport Queues on $Server are now active." 152 | Set-ServerComponentState $Server -Component HubTransport -State Active -Requester Maintenance 153 | 154 | Write-Host "$Server is now fully out of maintenance mode. You should now redistribute active database copies in the DAG." -ForegroundColor Green 155 | 156 | 157 | 158 | } 159 | 160 | function Get-ExDagMaintenance { 161 | <# 162 | .NOTES 163 | Written by Justin Beeden 164 | V1.3 12.05.2013 165 | .SYNOPSIS 166 | Checks Exchange 2013 DAG nodes maintenance mode settings. 167 | .DESCRIPTION 168 | Checks Exchange 2013 DAG nodes maintenance mode settings. 169 | http://technet.microsoft.com/en-us/library/dd298065%28v=exchg.150%29.aspx#Pm 170 | .PARAMETER Server 171 | Specifies the DAG node Server name to checked for maintenance mode settings. 172 | .EXAMPLE 173 | PS> .\Get2013DagServerMaintenance.ps1 -Server Server1 174 | .EXAMPLE 175 | PS> .\Get2013DagServerMaintenance.ps1 Server1 176 | #> 177 | 178 | #Requires -version 3.0 179 | 180 | [CmdletBinding()] 181 | Param( 182 | [Parameter(Position=0, Mandatory = $true, 183 | HelpMessage="Enter the name of DAG Server to check for Maintenance mode.")] 184 | [string]$Server 185 | ) 186 | 187 | #Shows if the server has been placed into maintenance mode 188 | Get-ServerComponentState $Server | Where {$_.Component -ne "Monitoring" -and $_.Component -ne "RecoveryActionsEnabled"} | ft Component,State -Autosize 189 | 190 | #Shows if the server is not hosting any active database copies 191 | Get-MailboxServer $Server | ft DatabaseCopy* -Autosize 192 | 193 | #Shows if that the cluster node is paused 194 | Get-ClusterNode $Server | fl 195 | 196 | #Shows that all transport queues have been drained 197 | Get-Queue -Server $Server 198 | 199 | } 200 | 201 | #Function to check all transport queues except Poison and Shadow queues are empty 202 | function CheckQueues() { 203 | $MessageCount = Get-Queue -Server $Server | Where {$_.Identity -notlike "*\Poison" -and $_.Identity -notlike"*\Shadow\*"} | Select MessageCount | Where {$_.MessageCount -ne 0} 204 | if($MessageCount){ 205 | Write-Host "$Server still has messages in transport queue, will check again in 30 seconds..." -ForegroundColor Yellow 206 | Start-Sleep -s 30 207 | CheckQueues 208 | } elseif($StopTransport){ 209 | Write-Host "Transport queues are empty, trying to stop transport services." -ForegroundColor Green 210 | try { 211 | Stop-Service MSExchangeFrontendTransport,MSExchangeTransport 212 | } 213 | catch { 214 | Write-Warning "Could not Stop Transport Services! Try stopping manually?" 215 | } 216 | } else{ 217 | Write-Host "Transport queues are empty." -ForegroundColor Green 218 | } 219 | } 220 | 221 | #Function to check all active database copies have been moved to another member of the DAG 222 | function CheckActiveDatabase() { 223 | $ActiveDatabase = Get-MailboxDatabaseCopyStatus -Server $Server | Where {$_.Status -eq 'Mounted'} 224 | if($ActiveDatabase){ 225 | Write-Host "$Server is still hosting active database copies, will check again in 30 seconds..." -ForegroundColor Yellow 226 | Start-Sleep -s 30 227 | CheckActiveDatabase 228 | } else{ 229 | Write-Host "All active database copies have been moved." -ForegroundColor Green 230 | } 231 | } 232 | 233 | #Function to check on DAGs File Share Witness if needed by DAG 234 | function CheckFSW(){ 235 | $FSW = Get-DatabaseAvailabilityGroup -Identity $Server.DatabaseAvailabilityGroup -Status | Where {$_.WitnessShareInUse -eq 'InvalidConfiguration'} 236 | if($FSW){ 237 | Throw "There is an issue with this DAGs File Share Witness, fix BEFORE doing node maintenance." 238 | } else { 239 | Write-Host "DAG File Share Witness OK or not in use." -ForegroundColor Green 240 | } 241 | } -------------------------------------------------------------------------------- /ExVirtualDir.ps1: -------------------------------------------------------------------------------- 1 | function Get-VirtualDir { 2 | param( 3 | $ExchangeServer, 4 | [switch]$AdProp 5 | ) 6 | 7 | foreach($server in $ExchangeServer) { 8 | 9 | $param = @{ 10 | 'Server' = $server; 11 | 'ADPropertiesOnly' = $true; 12 | 'ErrorAction' = 'Stop'; 13 | } 14 | 15 | try { 16 | $owa = Get-OwaVirtualDirectory @param 17 | $ews = Get-WebServicesVirtualDirectory @param 18 | $oab = Get-OabVirtualDirectory @param 19 | $mapi = Get-MapiVirtualDirectory @param 20 | $autodiscover = Get-ClientAccessService -Identity $server 21 | $oa = Get-OutlookAnywhere @param 22 | $eas = Get-ActiveSyncVirtualDirectory @param 23 | 24 | $out = @{ 25 | 'internal' = @{ 26 | 'Server' = $server 27 | 'OWA' = $owa.InternalUrl 28 | 'EWS' = $ews.InternalUrl 29 | 'OAB' = $oab.InternalUrl 30 | 'EAS' = $eas.InternalUrl 31 | 'Mapi' = $mapi.InternalUrl 32 | 'OutlookAnywhere' = $oa.InternalHostname 33 | 'Autodiscover' = $autodiscover.AutoDiscoverServiceInternalUri 34 | }; 35 | 'external' = @{ 36 | 'Server' = $server 37 | 'OWA' = $owa.ExternalUrl 38 | 'Ews' = $ews.ExternalUrl 39 | 'OAB' = $oab.ExternalUrl 40 | 'EAS' = $eas.ExternalUrl 41 | 'Mapi' = $mapi.ExternalUrl 42 | 'OutlookAnywhere' = $oa.ExternalHostname 43 | } 44 | } 45 | 46 | $out 47 | } catch { 48 | Write-Warning "Could not connect to $_" 49 | } 50 | 51 | } 52 | 53 | } 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Exchange_TimeBasedInboxRule.ps1: -------------------------------------------------------------------------------- 1 | # just testing... 2 | # connect to exchange online 3 | # Connect-Exchange -Online -Credential (Get-Credential) 4 | # 5 | # update rule daily (scheduled task) 6 | # Get-InboxRule -Mailbox tom -Identity move_night | 7 | # Set-InboxRule 8 | #-ExceptIfReceivedAfterDate (Get-Date 06:00) 9 | #-ExceptIfReceivedBeforeDate (Get-Date 15:00) 10 | # 11 | #Get-Mailbox tom | New-OffHoursFolder -Name "_offhours" -Verbose 12 | #Get-Mailbox tom | Get-OffHoursFolder -Name night 13 | #Get-Mailbox tom | Get-OffHoursRule -Name _offhours 14 | #Get-Mailbox tom | New-OffHoursRule -Name move_offhours -MoveToFolder _offhours -StartTime 08:00 -EndTime 17:00 -Verbose 15 | # 16 | 17 | function Connect-Exchange 18 | { 19 | [CmdletBinding()] 20 | Param 21 | ( 22 | # Credential used for connection 23 | [Parameter(Mandatory=$true)] 24 | [pscredential] 25 | $Credential 26 | ) 27 | $params = @{ 28 | ConnectionUri = "https://outlook.office365.com/powershell-liveid/"; 29 | ConfigurationName = "Microsoft.Exchange"; 30 | Credential = $Credential; 31 | Authentication = "Basic"; 32 | AllowRedirection = $true; 33 | } 34 | try { 35 | Write-Verbose "Trying to connect to $($params.ConnectionUri)" 36 | $sExch = New-PSSession @params -ErrorAction Stop -ErrorVariable ExchangeSessionError -Verbose:$false 37 | Import-PSSession $sExch 38 | } catch { 39 | Write-Warning "Could not connect to Exchange $($ExchangeSessionError.ErrorRecord)" 40 | } 41 | } 42 | 43 | # Returns Inbox Rule for a Mailbox 44 | # If rulename or mailbox not found, returns nothing 45 | function Get-OffHoursRule { 46 | [CmdletBinding()] 47 | param ( 48 | [Parameter(ValueFromPipeline=$true)] 49 | [ValidateNotNullOrEmpty()] 50 | [string] 51 | $Mailbox, 52 | [ValidateNotNullOrEmpty()] 53 | [string] 54 | $Name 55 | ) 56 | process { 57 | Get-InboxRule -Mailbox $mailbox -Identity $Name -ErrorAction SilentlyContinue 58 | } 59 | } 60 | 61 | function New-OffHoursRule { 62 | [CmdletBinding()] 63 | param ( 64 | [Parameter(ValueFromPipeline=$true)] 65 | [ValidateNotNullOrEmpty()] 66 | $Mailbox, 67 | [ValidateNotNullOrEmpty()] 68 | [string] 69 | $Name, 70 | [ValidateNotNullOrEmpty()] 71 | [string] 72 | $MoveToFolder, 73 | $StartTime, 74 | $EndTime 75 | ) 76 | process { 77 | # Check if target folder already exists 78 | $mbxFolder = Get-OffHoursFolder -Mailbox $Mailbox -Name $MoveToFolder 79 | # Create folder if doesn't exist 80 | if(-not($mbxFolder)){ 81 | $mbxFolder = New-OffHoursFolder -Mailbox $Mailbox -Name $MoveToFolder 82 | } 83 | # create folder id string in format: mailbox:\foldername 84 | $folderId = $Mailbox.Identity,$mbxFolder.Name -join ":\" 85 | Write-Verbose "Folder Id is $folderId" 86 | # Create Rule 87 | if(-not(Get-OffHoursRule -Mailbox $Mailbox -Name $Name)){ 88 | $params = @{ 89 | Mailbox = $Mailbox; 90 | Name = $Name; 91 | ExceptIfReceivedAfterDate = (Get-Date $StartTime).ToUniversalTime(); 92 | ExceptIfReceivedBeforeDate = (Get-Date $EndTime).ToUniversalTime(); 93 | MoveToFolder = $folderId; 94 | } 95 | Write-Verbose "Create Rule $Name in Mailbox $Mailbox" 96 | Write-Verbose "Move mails before $StartTime and after $EndTime to folder: $FolderId" 97 | New-InboxRule @params 98 | } 99 | } 100 | } 101 | 102 | function Update-OffHoursRule { 103 | [CmdletBinding()] 104 | param ( 105 | [Parameter(ValueFromPipeline=$true)] 106 | [ValidateNotNullOrEmpty()] 107 | $Mailbox, 108 | $Name, 109 | $StartTime, 110 | $EndTime 111 | ) 112 | process { 113 | $params = @{ 114 | ExceptIfReceivedAfterDate = (Get-Date $StartTime).ToUniversalTime(); 115 | ExceptIfReceivedBeforeDate = (Get-Date $EndTime).ToUniversalTime(); 116 | } 117 | Get-OffHoursRule -Mailbox $Mailbox -Name $Name | Set-InboxRule @params 118 | } 119 | } 120 | 121 | function Get-OffHoursFolder { 122 | [CmdletBinding()] 123 | param ( 124 | [Parameter(ValueFromPipeline=$true)] 125 | [ValidateNotNullOrEmpty()] 126 | [string] 127 | $Mailbox, 128 | [ValidateNotNullOrEmpty()] 129 | [string] 130 | $Name 131 | ) 132 | process { 133 | Get-MailboxFolder -Identity "$Mailbox`:\$Name" -ErrorAction SilentlyContinue 134 | } 135 | } 136 | 137 | function New-OffHoursFolder { 138 | [CmdletBinding()] 139 | param ( 140 | [Parameter(ValueFromPipeline=$true)] 141 | [ValidateNotNullOrEmpty()] 142 | [string] 143 | $Mailbox, 144 | [ValidateNotNullOrEmpty()] 145 | [string] 146 | $Name 147 | ) 148 | process { 149 | if(Get-MailboxFolder -Identity "$Mailbox`:\$Name" -ErrorAction SilentlyContinue) { 150 | Write-Verbose "Folder $Name exists in Mailbox $($Mailbox.Identity)" 151 | } else { 152 | New-MailboxFolder -Parent $Mailbox -Name $Name 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /Find-UniqueIP.ps1: -------------------------------------------------------------------------------- 1 | function Find-UniuqeClientIP { 2 | <# 3 | .Synopsis 4 | Find and list unique client IPs in IIS logs. 5 | .DESCRIPTION 6 | This function was created for the Scripting Games 2013. 7 | This function uses regular expression to find IP addresses withing one or more IIS log files. 8 | You need to specify a folder containing one or more logfiles with a specified extension. The Filter parameter 9 | can be used to specify a file extension like *.log, *.txt. 10 | The Pattern 11 | parameter can be used to select a subset of client IP addresses. 12 | .EXAMPLE 13 | Find-UniqueClientIP -Path C:\temp\LogFiles 14 | 15 | This example finds unique client IP addresses in all .log files within C:\temp\LogFile 16 | .EXAMPLE 17 | Find-UniqueClientIP -Path C:\temp\LogFiles -Filter *.txt 18 | 19 | This example finds unique client IP addresses in all .txt files within C:\temp\LogFile. 20 | .EXAMPLE 21 | Find-UniqueClientIP -Path C:\temp\LogFiles -Pattern "192.168.*" -Verbose 22 | 23 | This example finds unique client IP addresses in all .log files within C:\temp\LogFile. 24 | Only IP addresses starting with "192.168." are included in the output. 25 | .OUTPUTS 26 | [string] 27 | #> 28 | [CmdletBinding(PositionalBinding=$true, 29 | ConfirmImpact='Medium')] 30 | [OutputType([string])] 31 | Param 32 | ( 33 | # Specify a folder containing one or more IIS log files with *.log extension. 34 | [Parameter(Mandatory=$true, 35 | ValueFromPipeline=$true, 36 | ValueFromPipelineByPropertyName=$true, 37 | Position=0)] 38 | [ValidateScript({Test-Path -Path $PSItem -PathType Container})] 39 | [Alias("LogFolder")] 40 | [System.IO.DirectoryInfo] 41 | $Path, 42 | 43 | # Specify a string filter to select an subset of client IP addresses. 44 | [Parameter(Mandatory=$false, 45 | Position=1)] 46 | [ValidateNotNull()] 47 | [ValidateNotNullOrEmpty()] 48 | [Alias("IpAddressPattern")] 49 | [string] 50 | $Pattern = "*", 51 | 52 | # specify which file extensions to include, like *.txt. Default to *.log. 53 | [Parameter(Mandatory=$false, 54 | Position=2)] 55 | [ValidateNotNull()] 56 | [ValidateNotNullOrEmpty()] 57 | [ValidatePattern('^\*\.\w{3}$')] 58 | [Alias("Extension")] 59 | [string] 60 | $Filter = "*.log" 61 | ) 62 | 63 | # regex used to match ip addersses in logfiles 64 | $RegExPattern = '\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b' 65 | 66 | # initialize variable and build the path used with select-string 67 | $filtered = @() 68 | $LogPath = Join-Path -Path $Path -ChildPath $Filter 69 | Write-Verbose "Path is: $LogPath" 70 | 71 | # use -matchall to get all IPs, first match is "s-ip"; second match is "c-ip"; using strings makes it easier 72 | $PatternMatches = Select-String -Path $LogPath -Pattern $RegExPattern -AllMatches | Select-Object -Property @{n="ServerIP";e={$PSItem.matches[0].toString()}},@{n="ClientIP";e={$PSItem.matches[1].toString()}} 73 | 74 | Write-Verbose "Applying filter pattern: $Pattern" 75 | 76 | foreach ($match in $PatternMatches) { 77 | # filter the ClientIP, this is 50% faster than using where-object 78 | if ($match.clientIP -like $Pattern) { 79 | # save all objects witch matching ClientIP in a container 80 | $filtered += $match 81 | } 82 | } 83 | # writing string values to the pipeline 84 | $filtered.clientIP | select -Unique 85 | } -------------------------------------------------------------------------------- /Get-AdAuditReport.ps1: -------------------------------------------------------------------------------- 1 | function Get-ADAuditReport { 2 | <# 3 | .Synopsis 4 | Get 20 random users from Active Directory. 5 | .DESCRIPTION 6 | This function gets a number of random users from Active Directory and displays the following information about them: SamAccountName, Department, Title, LastLogonTimeStamp, PasswordLastSet, Enabled, LockedOut. 7 | The number of users to query can be specified using the -ResultSetSize parameter, the number of random users to select out of the result set can be specified using the -Count parameter. 8 | The function creates an HTML report at a location spcified by -Path. The report will be opened using the default browser. 9 | If the ActiveDirectory PowerShell Module cannot be loaded locally, the function tries to create a PSRemoting session with a DC found by FindDomainController(). The -DomainController and -Credential parameters 10 | can be used to connect to a spcifiy Domain Contoller using specified credentials. 11 | If the ActiveDirectory PowerShell Module is available locally, it will always be preferd and -DomainController is ignored. 12 | .EXAMPLE 13 | Get-AdAuditReport -Path C:\temp\report.htm 14 | 15 | This example gets 512 users from Active Directory, it then randomly selects 20 of them and creates an audit report at c:\temp\report.htm. The report will be opened using the default browser. 16 | .EXAMPLE 17 | Get-AdAuditReport -Path C:\temp\report.htm -Count 40 -PassThru 18 | 19 | This example gets 512 users from Active Directory, it then randomly selects 40 of them and creates an audit report at c:\temp\report.htm. The report will be opened using the default browser. 20 | It also writes psobjects to the pipeline. 21 | .EXAMPLE 22 | Get-AdAuditReport -Path C:\temp\report.htm -DomainController dc01 -Credential (Get-Credential) -ResultSetSize 1000 -Count 10 23 | 24 | If the ActiveDirectory Module cannot be imported, this example tries to establish a PsRemoting session with dc01 using the credentials submitted by Get-Credential. 25 | It will then get 1000 users from AD and randomly select 10 of them. The report will again be generated at C:\temp\report.htm and be opened using the default browser. 26 | .OUTPUTS 27 | [psobject] 28 | .NOTES 29 | This function was created for the Scripting Games 2013. 30 | Author: thomas torggler; @torggler 31 | Date: 2013-05-20 32 | #> 33 | [CmdletBinding()] 34 | [OutputType([psobject])] 35 | Param 36 | ( 37 | # Specify a path for the HTML report, filename must end in html or htm. 38 | [Parameter(Mandatory=$true, 39 | Position=0)] 40 | [ValidatePattern("\.html$|\.htm$")] 41 | [Alias("Report")] 42 | [System.IO.FileInfo] 43 | $Path, 44 | 45 | # Specify the number of random accounts to get from AD. Defaults to 20. 46 | [Parameter(Position=1)] 47 | [ValidateRange(1,1000)] 48 | [int] 49 | $Count = 20, 50 | 51 | # Specify Domain Controller to connect to, uses FindDomainController() as a default value. 52 | [Parameter(Position=2)] 53 | [ValidateNotNull()] 54 | [ValidateNotNullorEmpty()] 55 | [Alias("DC")] 56 | [string] 57 | $DomainController = [System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain().FindDomainController().Name, 58 | 59 | # Specify credentials to connect to the Domain Controller. 60 | [Parameter(Mandatory=$false)] 61 | [ValidateNotNull()] 62 | [ValidateNotNullOrEmpty()] 63 | [System.Management.Automation.Credential()] 64 | $Credential = [System.Management.Automation.PSCredential]::Empty, 65 | 66 | # Specify ResultSetSize for Get-ADUser command. Defaults to 512. 67 | [Parameter(Position=3)] 68 | [ValidateRange(1,4000)] 69 | [Alias("Set")] 70 | [int] 71 | $ResultSetSize = 512, 72 | 73 | # Speficy ResultPageSize for Get-ADUser command. Defaults to 256. 74 | [Parameter(Position=4)] 75 | [ValidateRange(1,2000)] 76 | [Alias("Page")] 77 | [int] 78 | $ResultPageSize = 256, 79 | 80 | # Output objects to the pipeline 81 | [switch] 82 | $PassThru 83 | ) 84 | 85 | ### no use for begin, process, end blocks as there is nothing piped in here. 86 | 87 | ### try to create an empty new repot file to check permissions 88 | try { 89 | New-Item -Path $Path -ItemType File -Force -ErrorAction Stop -ErrorVariable CreatePathError | Out-Null 90 | } catch { 91 | Write-Warning -Message "Could not create file: $($CreatePathError.ErrorRecord) Report will not be available" 92 | } 93 | 94 | ### try importing ActiveDirectory Module 95 | if ((Get-Module -ListAvailable ActiveDirectory) -ne $null) { 96 | Write-Verbose "ActiveDirectory Module found, trying to import" 97 | try { 98 | Import-Module ActiveDirectory -ErrorAction Stop -ErrorVariable ImportModuleError 99 | } catch { 100 | Write-Warning "Could not import ActiveDirectory PowerShell Module $($ImportModuleError.ErrorRecord)" 101 | } 102 | } else { 103 | Write-Verbose "Active Directory Module not found, trying to connect to $DomainController" 104 | try { 105 | $ADSession = New-PSSession -Name AD -ComputerName $DomainController -Credential $Credential -ErrorAction Stop -ErrorVariable PSSessionError 106 | Invoke-Command -Session $ADSession -ScriptBlock {Import-Module ActiveDirectory} 107 | Import-PSSession $ADSession -CommandName Get-ADUser | Out-Null 108 | } catch { 109 | Write-Warning "Could not connect to $DomainController $($PSSessionError.ErrorRecord)" 110 | } 111 | } 112 | 113 | if (Get-Command Get-ADUser -ErrorAction SilentlyContinue) { 114 | Write-Verbose "Get-ADUser command found, getting $ResultSetSize users" 115 | 116 | ### Getting AD Users with needed properties, using LastLogonTimeStamp because it is replicated between DomainControllers. 117 | ### LastLogon would provide more up to date information, but is only updated on the validating DC. 118 | 119 | $getAdUser = @{ 120 | 'Filter'='*'; 121 | 'ResultSetSize'=$ResultSetSize; 122 | 'ResultPageSize'=$ResultPageSize 123 | } 124 | ### Getting users from AD 125 | $RandomUsers = Get-ADUser @getAdUser -Properties Department, Title, LockedOut, LastLogonTimeStamp, PasswordLastSet | Get-Random -Count $Count 126 | $AuditReport = @() 127 | 128 | foreach ($User in $RandomUsers) { 129 | $AuditInfo = [ordered]@{ 130 | 'Username' = $User.SamAccountName; 131 | 'Department' = $User.Department; 132 | 'Title' = $User.Title; 133 | 'LastLogonTime' = [datetime]::FromFileTime($User.LastLogonTimeStamp); 134 | 'PasswordLastSet' = $User.PasswordLastSet; 135 | 'AccountDisabled' = -not $User.Enabled; 136 | 'AccountLockedOut' = $User.LockedOut 137 | } 138 | if ($User.LastLogonTimeStamp -eq $null) { 139 | $AuditInfo.LastLogonTime = "never" 140 | } 141 | if ($User.PasswordLastSet -eq $null) { 142 | $AuditInfo.PasswordLastSet = "never" 143 | } 144 | 145 | ### Add all user information objects to a single object 146 | $AuditReport += New-Object -TypeName PsObject -Property $AuditInfo 147 | 148 | } # end foreach $user 149 | 150 | ### if PassThru parameter is set, write objects to the pipeline 151 | if ($PassThru){ 152 | Write-Output $AuditReport 153 | } 154 | 155 | ### parameters for ConvertTo-Html 156 | $htmlParam = @{ 157 | 'Title'='Active Directory Audit Report' 158 | 'PreContent'="
136 |
138 |
Drive | 141 |Size(GB) | 142 |FreeSpace(MB) | 143 |
---|---|---|
$($item.DeviceID) | 167 |$(“{0:N2}” -f($item.Size/1GB)) | 168 |$(“{0:N2}” -f($item.FreeSpace/1MB)) |
195 |
197 |
198 |
Computer Name | 201 |Operating System Name | 202 |Operating System Build Number | 203 |Service Pack Version | 204 |CPU Sockets | 205 |CPU Cores | 206 |Processor Architecture | 207 |Total Physical Memory (MB) | 208 |
---|---|---|---|---|---|---|---|
$($ReportData.ComputerName) | $($ReportData.OSName) | $($ReportData.OSBuild) | $($ReportData.ServicePack) | $($ReportData.Sockets) | $($ReportData.Cores) | $($ReportData.ProcessorArchitecture) | $($ReportData.PhysicalMemory) |
---
220 | Check out the Scripting Games at: http://scriptinggames.org
221 |
222 | "
223 |
224 | # Combine the above pieces to a single HTML container
225 | $htmlOut = $htmlHead + $htmlTable +$htmlTail
226 |
227 | # Write HTML to file
228 | $htmlOut | Out-File $Report
229 | }
230 | } # End if $Continue
231 | } # End ForEach $ComputerName
232 | } # End Process
233 |
234 | End
235 | {
236 | # Show the HTML Report in a browser
237 | if ($Report) {
238 | # Report has been specified, check if there is a file
239 | if (Test-Path $Report) {
240 | Write-Verbose "Opening $Report ..."
241 | Start-Process -FilePath $Report
242 | }
243 | }
244 | } # End End :)
245 | } # End Get-InventoryInfo
--------------------------------------------------------------------------------
/Get-TeamsNetAssessmentStats.ps1:
--------------------------------------------------------------------------------
1 | function Get-Jitter {
2 | [CmdletBinding()]
3 | param (
4 | $Filename
5 | )
6 | process {
7 | (Select-String -Path $Filename -Pattern "jitter:\s+(\d+\.\d+)\sms").matches.groups.where{$_.name -eq 1}.value | Measure-Object -Minimum -Maximum -Average
8 | }
9 | }
10 |
11 | function Get-PLoss {
12 | [CmdletBinding()]
13 | param (
14 | $Filename
15 | )
16 | process {
17 | (Select-String -Path $Filename -Pattern "loss\srate:\s+(\d+\.\d+)").matches.groups.where{$_.name -eq 1}.value | ForEach-Object {[double]$_*100} | Measure-Object -Minimum -Maximum -Average
18 | }
19 | }
20 |
21 |
22 | function Get-Latency {
23 | [CmdletBinding()]
24 | param (
25 | $Filename
26 | )
27 | process {
28 | (Select-String -Path $Filename -Pattern "latency:\s+(\d+(\.\d+)?)").matches.groups.where{$_.name -eq 1}.value | Measure-Object -Minimum -Maximum -Average
29 | }
30 | }
31 |
32 | function Get-TeamsNetAssessmentStats {
33 | [CmdletBinding()]
34 | param (
35 | $Filename
36 | )
37 | process {
38 | Write-Information "Packet Loss" -InformationAction Continue
39 | Get-PLoss -Filename $Filename
40 | Write-Information "Jitter" -InformationAction Continue
41 | Get-Jitter -Filename $Filename
42 | Write-Information "Latency" -InformationAction Continue
43 | Get-Latency -Filename $Filename
44 | }
45 |
46 | }
47 |
48 | #Get-TeamsNetAssessmentStats -Filename "C:\Users\thomas.torggler\Experts Inside GmbH\DT Swiss - Netzwerk Assessment\Biel - LAN\TeamsSkypeStatsDetail.txt"
49 |
50 | Get-TeamsNetAssessmentStats -Filename "C:\Users\thomas.torggler\Experts Inside GmbH\unisg - Network Assessment\StGallen - WIFI\TeamsSkypeStatsDetail.txt"
51 |
52 |
--------------------------------------------------------------------------------
/GitHub.ps1:
--------------------------------------------------------------------------------
1 |
2 | function New-GHFile {
3 | [CmdletBinding()]
4 | param (
5 | [Parameter(Mandatory)]
6 | [string]$Path,
7 |
8 | [Parameter(Mandatory)]
9 | [string]$Owner,
10 |
11 | [Parameter(Mandatory)]
12 | [string]$Repository,
13 |
14 | [Parameter(Mandatory)]
15 | [string]$Token,
16 |
17 | [Parameter(Mandatory)]
18 | [string]$Content,
19 |
20 | [string]$Message
21 | )
22 | $Headers = @{
23 | Authorization = "token $Token"
24 | Accept = "application/vnd.github.v3+json"
25 | }
26 | $Body = @{
27 | message = $Message
28 | content = $(ConvertTo-Base64 -String $Content)
29 | }
30 | $uri = "https://api.github.com/repos/{0}/{1}/contents/{2}" -f $Owner,$Repository,$Path
31 | Invoke-RestMethod -Method PUT -Uri $Uri -Headers $Headers -Body ($Body | ConvertTo-Json)
32 | }
33 |
34 |
35 | function Get-GHFile {
36 | [CmdletBinding()]
37 | param (
38 | [Parameter(Mandatory)]
39 | [string]$Path,
40 |
41 | [Parameter(Mandatory)]
42 | [string]$Owner,
43 |
44 | [Parameter(Mandatory)]
45 | [string]$Repository,
46 |
47 | [Parameter(Mandatory)]
48 | [string]$Token
49 | )
50 | $Headers = @{
51 | Authorization = "token $Token"
52 | Accept = "application/vnd.github.v3+json"
53 | }
54 | $uri = "https://api.github.com/repos/{0}/{1}/contents/{2}" -f $Owner,$Repository,$Path
55 | Invoke-RestMethod -Method Get -Uri $Uri -Headers $Headers
56 | }
57 |
58 |
59 | function Remove-GHFile {
60 | [CmdletBinding(SupportsShouldProcess)]
61 | param (
62 | [Parameter(ParameterSetName="Path",Mandatory)]
63 | [string]$Path,
64 |
65 | [Parameter(ParameterSetName="Path",Mandatory)]
66 | [string]$Owner,
67 |
68 | [Parameter(ParameterSetName="Path",Mandatory)]
69 | [string]$Repository,
70 |
71 | [Parameter(ParameterSetName="Path",Mandatory)]
72 | [string]$Sha,
73 |
74 | [Parameter(ParameterSetName="Path")]
75 | [string]$Message,
76 |
77 | [Parameter(Mandatory)]
78 | [string]$Token,
79 |
80 | [Parameter(ParameterSetName="IO",ValueFromPipeline)]
81 | $InputObject
82 | )
83 |
84 | if($InputObject){
85 | $uri = $InputObject.url
86 | $Sha = $InputObject.sha
87 | $Message = "Deletes item $uri"
88 | } else {
89 | $uri = "https://api.github.com/repos/{0}/{1}/contents/{2}" -f $Owner,$Repository,$Path
90 | }
91 |
92 | $Headers = @{
93 | Authorization = "token $Token"
94 | Accept = "application/vnd.github.v3+json"
95 | }
96 | $Body = @{
97 | message = $Message
98 | sha = $Sha
99 | }
100 | if($PSCmdlet.ShouldProcess($uri,"Remove item")){
101 | Write-Verbose -Message ($Body | ConvertTo-Json -Compress)
102 | Invoke-RestMethod -Method Delete -Uri $Uri -Headers $Headers -Body ($Body | ConvertTo-Json)
103 | }
104 | }
105 |
106 |
--------------------------------------------------------------------------------
/Invoke-DiskSpd.ps1:
--------------------------------------------------------------------------------
1 |
2 | <#PSScriptInfo
3 |
4 | .VERSION 0.1
5 |
6 | .GUID c3e1577a-fb7f-427b-b423-8126ee17dd9b
7 |
8 | .AUTHOR @torggler
9 |
10 | .COMPANYNAME
11 |
12 | .COPYRIGHT
13 |
14 | .TAGS
15 |
16 | .LICENSEURI
17 |
18 | .PROJECTURI
19 |
20 | .ICONURI
21 |
22 | .EXTERNALMODULEDEPENDENCIES
23 |
24 | .REQUIREDSCRIPTS
25 |
26 | .EXTERNALSCRIPTDEPENDENCIES
27 |
28 | .RELEASENOTES
29 |
30 |
31 | #>
32 |
33 | <#
34 | .Synopsis
35 | A wrapper for the DiskSpd utility
36 | .DESCRIPTION
37 | Long description
38 | .EXAMPLE
39 | Example of how to use this cmdlet
40 | .EXAMPLE
41 | Another example of how to use this cmdlet
42 | .INPUTS
43 | Inputs to this cmdlet (if any)
44 | .OUTPUTS
45 | Output from this cmdlet (if any)
46 | .COMPONENT
47 | The component this cmdlet belongs to
48 | .ROLE
49 | The role this cmdlet belongs to
50 | .FUNCTIONALITY
51 | The functionality that best describes this cmdlet
52 | #>
53 |
54 | [CmdletBinding(DefaultParameterSetName='Parameter Set 1',
55 | PositionalBinding=$false,
56 | ConfirmImpact='Medium')]
57 | [Alias('diskspd')]
58 | [OutputType([psobject])]
59 | Param
60 | (
61 | # Specify the path to the Diskspd.exe file
62 | [Parameter(Mandatory=$false,
63 | Position=0,
64 | ParameterSetName='Parameter Set 1')]
65 | [ValidateNotNull()]
66 | [ValidateNotNullOrEmpty()]
67 | [System.IO.FileInfo]
68 | $Path=(Join-Path -Path $env:USERPROFILE -ChildPath "Downloads\Diskspd-v2.0.15\amd64fre\diskspd.exe"),
69 |
70 | # Specify a filepath where the testfile will be created. Default is TEMP
71 | [System.IO.FileInfo]
72 | $TestFilePath = (Join-Path -Path $env:TEMP -ChildPath "diskspdtest.dat"),
73 |
74 | # Specify a path to the LogFile
[Parameter(Mandatory=$false)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[System.IO.FileInfo]
$LogFile="$env:TEMP\log-Invoke-DiskSpd.txt",
75 |
76 | # Specify the filesize for the test file. Default is 1GB
77 | [int]
78 | $TestFileSize = 1GB,
79 |
80 | # Specify the block size in bytes. Default is 4kb
81 | [int]
82 | $BlockSize = 4kb,
83 |
84 | # Specify percentage of writes. Default is 50. 0 indicates 100% read operations.
85 | [int]
86 | [ValidateRange(0,100)]
87 | $WritePercentage = 50,
88 |
89 | [int]
90 | $OutstandingIos,
91 |
92 | # Specify duration in seconds. Default is 60.
93 | [int]
94 | [ValidateRange(1,86400)]
95 | $Duration = 60,
96 |
97 | # Specify warmup duration before measurement starts in seconds. Default is 5 seconds.
98 | [int]
99 | [ValidateRange(1,86400)]
100 | $WarmUp = 5,
101 |
102 | # Specify number of threads to use for workload. Default is number of CPU cores.
103 | [int]
104 | $Threads,
105 |
106 | # Use a buffer, filled with random data, of the specified size, as source for write operations.
107 | # If not specified, a repeating pattern is used to fill write buffers.
108 | [int]
109 | $RandomWriteBufferSize,
110 |
111 | # Delete the testfile after finishing. If not specified, the testfile will not be deleted and can be used
112 | # for additional tests.
113 | [switch]
114 | $RemoveTestFile,
115 |
116 | # Do not capture latency data. Default is capture latency.
117 | [switch]
118 | $NoLatency,
119 |
120 | # Enable software and hardware caching. If TestFileSize fits into RAM, this essentially measures RAM performance.
121 | # Default is both soft/hardware caching disabled.
122 | [switch]
123 | $EnableCaching,
124 |
125 | # Random IO, if not specified, sequential-interlocked is used.
126 | [switch]
127 | $Random
128 |
129 | )
130 |
131 | #region set environment
# save the current location, then change location to the ResKit directory
$CurrentLocation = Get-Location
Set-Location $Path.DirectoryName
Write-Verbose "Changed Location to $($Path.DirectoryName)"
# delete existing logfile, and create a new one
Remove-Item -Path $logfile -ErrorAction SilentlyContinue
"$(Get-Date) Invoke-DiskSpd started" | Add-Content $LogFile
# Write location of logfile to host
Write-Host "LogFile: $LogFile" -ForegroundColor Yellow
132 |
133 | #endregion
134 |
135 | #region DiskSpd parameters
136 |
137 | $DiskSpd = ".\diskspd.exe"
138 | $DiskSpdParams = " -d$Duration -W$WarmUp -w$WritePercentage -b$BlockSize -c$TestFileSize"
139 |
140 | if(-not($NoLatency)) {
141 | $DiskSpdParams += " -L"
142 | }
143 |
144 | if(-not($EnableCaching)){
145 | $DiskSpdParams += " -h"
146 | }
147 |
148 | if($RandomWriteBufferSize) {
149 | $DiskSpdParams += " -Z$RandomWriteBufferSize"
150 | }
151 |
152 | if($OutstandingIos) {
153 | $DiskSpdParams += " -o$OutstandingIos"
154 | }
155 |
156 | if($Random) {
157 | $DiskSpdParams += " -r"
158 | } else {
159 | $DiskSpdParams += " -si"
160 | }
161 |
162 | if($Threads) {
163 | $DiskSpdParams += " -t$Threads"
164 | } else {
165 | # borrowed from diskspdbatch (technet gallery)
166 | # get CPU cores to determine number of threads (non-hyper-threaded)
167 | $processors = Get-CimInstance -ComputerName localhost Win32_Processor
168 | $Cores = 0
169 | if ( @($processors)[0].NumberOfCores) {
170 | $Cores = @($processors).Count * @($processors)[0].NumberOfCores
171 | } else {
172 | $Cores = @($processors).Count
173 | }
174 | $DiskSpdParams += " -t$Cores"
175 | }
176 |
177 | #endregion DiskSpd params
178 |
179 | Write-Verbose "Invoking $DiskSpd $DiskSpdParams `"$TestFilePath`""
180 |
181 | $DiskSpdOutput = Invoke-Expression -Command ($DiskSpd + $DiskSpdParams + " " + $TestFilePath)
182 | $DiskSpdOutput
183 |
184 | if ($RemoveTestFile) {
185 | Write-Verbose "Removing testfile at $TestFilePath"
186 | Remove-Item $TestFilePath
187 | }
188 |
#region reset environment
# set location back to where we have been originally
Set-Location $CurrentLocation
Write-Verbose "Changed Location back to original"
"$(Get-Date) Invoke-DiskSpd finished" | Add-Content $LogFile
189 |
190 | #endregion
191 |
--------------------------------------------------------------------------------
/Invoke-VocabTrainer.ps1:
--------------------------------------------------------------------------------
1 |
2 | [CmdletBinding()]
3 | param (
4 | [System.IO.FileInfo]
5 | $Path = "C:\Users\Thomas\OneDrive\Audio\vocab\vocab_noun.csv",
6 | $Count,
7 | [ValidateSet("de","it","en","us")]
8 | $SourceLanguage = "de",
9 | [ValidateSet("de","it","en","us")]
10 | $DestinationLanguage = "es"
11 | )
12 |
13 |
14 | try {
15 | [System.Collections.ArrayList]$csvImport = Import-Csv $Path -Encoding UTF7 -ErrorAction Stop
16 | }
17 | catch {
18 | Write-Warning "Could not import CSV file $Path"
19 | }
20 |
21 | # Randomize the list
22 | $csvImport = Get-Random -InputObject $csvImport -Count $csvImport.Count
23 |
24 |
25 | foreach ($item in $csvImport) {
26 |
27 | switch ($SourceLanguage) {
28 | "de" {
29 | $input = Read-Host -Prompt "`nWas heißt $($item.deutsch) in $DestinationLanguage"
30 | }
31 | "en" {
32 | $input = Read-Host -Prompt "`nWhat's $($item.english) in $DestinationLanguage"
33 | }
34 | "es" {
35 | $input = Read-Host -Prompt "`nQué es $($item.spanish) in $DestinationLanguage"
36 | }
37 | "it" {
38 | $input = Read-Host -Prompt "`nCom'è $($item.italiano) in $DestinationLanguage"
39 | }
40 | }
41 |
42 | }
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/M01Stats.ps1:
--------------------------------------------------------------------------------
1 | function Get-M01Stats {
2 | param(
3 | $ComputerName = "m01"
4 | )
5 |
6 | # kind of complicated
7 | #$sensors = sensors | Select-String -Pattern ":"
8 | #$sensorsTable = $sensors -replace ":","=" | ConvertFrom-StringData
9 |
10 | try {
11 | $xmrApi = Invoke-RestMethod -uri "http://$ComputerName`:16000/api.json" -ErrorAction Stop
12 | $hashrate = $xmrApi | Select-Object -ExpandProperty hashrate | Select-Object -ExpandProperty total | Select-Object -First 1
13 | } catch {
14 | Write-Warning "Could not connect to XMR Api"
15 | }
16 |
17 | $out = [ordered]@{
18 | "TimeStamp" = $(get-date -Format "yyyy-MM-dd HH:mm:ss")
19 | "Host" = $ComputerName;
20 | "Uptime" = $xmrApi.uptime
21 | "HashRate" = $hashrate
22 | }
23 | Write-Output (New-Object -TypeName psobject -Property $out)
24 | }
--------------------------------------------------------------------------------
/Microsoft.PowerShell_profile.ps1:
--------------------------------------------------------------------------------
1 | #######
2 | ### The actual $PROFILE only contains the following line to dot-source this file
3 | ### . $env:USERPROFILE\Git\PowerShell\Microsoft.PowerShell_profile.ps1
4 | ######
5 | $host.PrivateData.ErrorForegroundColor = 'white'
6 | ## Aliases... because of muscle memory :/
7 | New-Alias -Name ll -Value Get-ChildItem -ErrorAction SilentlyContinue
8 |
9 | function Invoke-AsAdmin {
10 | param($command)
11 | Start-Process pwsh -Verb RunAs -ArgumentList "-noprofile $command"
12 | }
13 |
14 | function Set-DnsOpen {
15 | param(
16 | $InterfaceIndex = 4
17 | )
18 | $command = "Set-DnsClientServerAddress -InterfaceIndex $InterfaceIndex -ServerAddresses ('208.67.222.222','208.67.220.220','2620:0:ccc::2','2620:0:ccd::2')"
19 | Invoke-AsAdmin $command
20 | }
21 |
22 | function Set-DnsCloudflare {
23 | param(
24 | $InterfaceIndex = 4
25 | )
26 | $command = "Set-DnsClientServerAddress -InterfaceIndex $InterfaceIndex -ServerAddresses ('1.1.1.1','1.0.0.1','2606:4700:4700::1111','2606:4700:4700::1001')"
27 | Invoke-AsAdmin $command
28 | }
29 |
30 | function Set-DnsDhcp {
31 | param(
32 | $InterfaceIndex = 4
33 | )
34 | $command = "Set-DnsClientServerAddress -InterfaceIndex $InterfaceIndex -ResetServerAddresses"
35 | Invoke-AsAdmin $command
36 | }
37 |
38 | # Chocolatey profile
39 | $ChocolateyProfile = "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
40 | if (Test-Path($ChocolateyProfile)) {
41 | Import-Module "$ChocolateyProfile"
42 | }
43 |
44 | dir "$home\Git\IT-Pro-Trashcan\tto\tools" -Filter *.ps1 | %{ . $_.FullName }
45 | Set-SecurityProtocol -Protocol Tls12
46 | if($PSVersionTable.platform -like "Win*"){
47 |
48 | $connectedIf = Get-NetRoute -DestinationPrefix 0.0.0.0/0 | Sort-Object -Property RouteMetric -Descending
49 | if($connectedIf){
50 | $dnsServers = (Get-DnsClientServerAddress -InterfaceIndex $connectedIf.IfIndex | Select-Object -ExpandProperty serveraddresses -Unique) -join ", "
51 | }
52 |
53 | $write = "
54 | ---
55 | IfAlias: $(($connectedIf.InterfaceAlias | Select-Object -Unique) -join ", ")
56 | IfIndex: $(($connectedIf.IfIndex | Select-Object -Unique) -join ", ")
57 | DNS Servers: $dnsServers
58 | Security Protcols: $(Get-SecurityProtocol)
59 | ---
60 | "
61 | Write-Host $write -ForegroundColor Yellow
62 |
63 | }
64 |
65 |
66 | function prompt {
67 | $pss = Get-PSSession | Where-Object Availability
68 | $cwd = (Get-Location).Path
69 | if($pss) {
70 | $WindowTitle = "Connected to: " + ($pss.ComputerName -join ", ")
71 | $info = $pss.ComputerName -join ", "
72 | $info += ": #$($MyInvocation.HistoryId)"
73 | } else {
74 | $WindowTitle = $cwd
75 | $info = "PS: #$($MyInvocation.HistoryId)"
76 | }
77 | if($Global:WindowTitlePrefix){
78 | $WindowTitle = $Global:WindowTitlePrefix,$WindowTitle -join ": "
79 | }
80 | $host.UI.RawUI.WindowTitle = $WindowTitle
81 | $host.UI.Write("Yellow", $host.UI.RawUI.BackGroundColor, "[$info]")
82 | " $($cwd.Replace($home,"~"))$('>' * ($nestedPromptLevel + 1)) ";
83 | }
84 |
85 | function Set-WindowTitle($String) {
86 | $Global:WindowTitlePrefix = $String
87 | }
88 |
89 |
90 | function Get-JekyllTitle {
91 | [CmdletBinding()]
92 | param (
93 | [string]
94 | $String
95 | )
96 | process {
97 | $date = Get-Date -Format "yyyy-MM-dd"
98 | $date,($string.ToLower() -replace "\W+","-") -join "-"
99 | }
100 | }
101 |
102 |
103 | # check if a new release of PowerShell Core is available on GitHub
104 | function Test-PSVersionGitHub {
105 | try {
106 | # get latest release from github atom feed
107 | $Release = Invoke-RestMethod https://github.com/PowerShell/PowerShell/releases.atom -ErrorAction Stop | Select-Object -First 1
108 | } catch {
109 | Write-Warning "Could not check for new version. $_ `n"
110 | break
111 | }
112 | # extract information from atom response
113 | $GitId = $Release.id -split "/" | Select-Object -Last 1
114 | $Download = -join("https://github.com",$Release.link.href)
115 | # Add information to dictionary for output
116 | $output = [ordered]@{
117 | "PSVersion" = $PSVersionTable.PSVersion;
118 | "GitCommitId" = $PSVersionTable.GitCommitId;
119 | "GitHubReleaseVersion" = $GitId;
120 | "GitHubReleaseLink" = $Download;
121 | }
122 | if($output.PSVersion -ne $output.GitCommitId){
123 | Write-Output (New-Object -TypeName psobject -Property $output)
124 | }
125 | }
126 |
127 | $env:Path += ";C:\Users\ThomasTorggler\OneDrive - Experts Inside AG\Tools;C:\Program Files\1Password CLI"
128 |
129 |
130 | function Test-macOSNetConnection {
131 | [CmdletBinding()]
132 | param (
133 | [System.Net.IPAddress]$IP4Address = '1.1.1.1',
134 | [System.Net.IPAddress]$IP6Address = '2606:4700:4700::1111',
135 | [string]$TestFqdn = "onprem.wtf",
136 | [string]$WebTest = "https://outlook.office365.com/owa/favicon.ico",
137 | [int]$Count = 1
138 | )
139 | $r = Invoke-Expression -command "ping $IP4Address -c $count"
140 | $r6 = Invoke-Expression -command "ping6 $IP6Address -c $count"
141 | $dg = netstat -nr | Select-String -Pattern default
142 |
143 | $dns = Invoke-Expression -Command "dig $TestFqdn +short"
144 | $dns6 = Invoke-Expression -Command "dig $TestFqdn AAAA +short"
145 |
146 | $web = Invoke-WebRequest -Uri $WebTest -Method head
147 |
148 | [PSCustomObject]@{
149 | ping = $r[-1..-2] -join ', '
150 | #ping6 = $r6[-1..-2] -join ', '
151 | dns = $dns -join ', '
152 | dns6 = $dns6 -join ', '
153 | web = $web.StatusDescription
154 | }
155 | }
156 |
157 |
158 | if($IsMacOS){
159 | Test-PSVersionGitHub
160 | New-Alias -Name tnc -Value Test-macOSNetConnection
161 | }
162 |
163 |
164 | ### version
165 |
166 | $PSReadLineVersion = (Get-Module -Name PSReadLine).Version.ToString()
167 | if($PSReadLineVersion -ge "2.2.6"){
168 | Set-PSReadLineOption -PredictionSource HistoryAndPlugin -PredictionViewStyle ListView
169 | }
--------------------------------------------------------------------------------
/Microsoft.PowerShell_profile_osx.ps1:
--------------------------------------------------------------------------------
1 | # Create a symbolic link for the file
2 | # mac
3 | # mkdir /Users/tto/.config/powershell
4 | # ln -s /Users/tto/git/PowerShell/Microsoft.PowerShell_profile_osx.ps1 /Users/tto/.config/powershell/Microsoft.PowerShell_profile.ps1
5 | # bash on win 10
6 | # mkdir /home/tto/.config/powershell
7 | # Copy-Item /mnt/c/Users/tto/OneDrive/_psscripts/git/PowerShell/Microsoft.PowerShell_profile_osx.ps1 $Profile -Force
8 |
9 | # Update PATH variable for Mac so that I can run most bash commands in PS
10 | # make sure new paths are inserted before existing
11 | $addToPath = @(
12 | "/usr/local/bin",
13 | "/opt/homebrew/opt/ruby/bin",
14 | "/opt/homebrew/bin",
15 | "/opt/homebrew/sbin",
16 | "/Users/tto/Library/Python/3.9/bin"
17 | )
18 | $newPath = ($addToPath -join ":"),$env:PATH -join ":"
19 | $env:PATH = $newPath
20 |
21 | # import modules for powercli
22 | function Import-PowerCliModules {
23 | Import-Module PowerCLI.Vds, PowerCLI.ViCore
24 | }
25 | New-Alias -Name ipcli -Value Import-PowerCliModules
26 |
27 | # check if a new release of PowerShell Core is available on GitHub
28 | function Test-PSVersionGitHub {
29 | try {
30 | # get latest release from github atom feed
31 | $Release = Invoke-RestMethod https://github.com/PowerShell/PowerShell/releases.atom -ErrorAction Stop | Select-Object -First 1
32 | } catch {
33 | Write-Warning "Could not check for new version. $_ `n"
34 | break
35 | }
36 | # extract information from atom response
37 | $GitId = $Release.id -split "/" | Select-Object -Last 1
38 | $Download = -join("https://github.com",$Release.link.href)
39 | # Add information to dictionary for output
40 | $output = [ordered]@{
41 | "PSVersion" = $PSVersionTable.PSVersion;
42 | "GitCommitId" = $PSVersionTable.GitCommitId;
43 | "GitHubReleaseVersion" = $GitId;
44 | "GitHubReleaseLink" = $Download;
45 | }
46 | Write-Output (New-Object -TypeName psobject -Property $output)
47 | }
48 | # powershell started checking for newer versions by itself
49 | # Test-PSVersionGitHub
50 |
51 | . ~/git/PowerShell/Microsoft.PowerShell_profile.ps1
--------------------------------------------------------------------------------
/New-FirewallRule.ps1:
--------------------------------------------------------------------------------
1 | function New-FirewallRule {
2 | Param(
3 | [string]$Name,
4 | [int]$Port,
5 | [string]$Protocol
6 | )
7 | $params = @{
8 | DisplayName = $Name;
9 | Action = 'Allow';
10 | Description = "$Name on $Protocol/$Port";
11 | Enabled = 1;
12 | Profile = 'Any';
13 | Protocol = $Protocol;
14 | PolicyStore = 'PersistentStore';
15 | LocalPort=$Port;
16 | ErrorAction = 'Stop';
17 | }
18 | try {
19 | $null = New-NetFirewallRule @params
20 | }
21 | catch {
22 | Write-Warning "Could not create firewall rule: $_"
23 | }
24 | }
25 |
26 | #New-FirewallRule -Port 6060 -Name "Allow SMTP"
--------------------------------------------------------------------------------
/New-SfBBackup.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | Backup Skype for Business / Lync Server Data.
4 | .DESCRIPTION
5 | This script exports Skype for Business / Lync Data and Settings according to the documentation availabe on TechNet.
6 | It is intended to be run as scheduled task, the Retention parameter can be used to indicate how long
7 | to keep existing backup files in the target directory.
8 | .EXAMPLE
9 | .\New-SfBBackup.ps1 -PoolFqdn lyncpool01.example.com -Path \\SERVER\Share\CSBackup
10 |
11 | This example exports Lync config and saves it into a subfolder at \\SERVER\Share\CSBackup
12 | .EXAMPLE
13 | .\New-SfBBackup.ps1 -PoolFqdn lyncpool01.example.com -Path \\SERVER\Share\CSBackup -Retention 10
14 |
15 | This example exports Skype for Business / Lync config and saves it into a subfolder at \\SERVER\Share\CSBackup.
16 | It deletes existing backups in the destination direcotry if they are older than 10 days.
17 | .ROLE
18 | The user must be member of the RTCUniversalServerAdmins group.
19 | .NOTES
20 | Author: Thomas Torggler; @torggler
21 | Date: 2018-03-17
22 | Version: 2.0
23 | 2.0 Updated Name, verbose output
24 | 1.1 Added Retention parameter and some error handling.
25 | 1.0: Basics
26 | To-do: Multiple pools, File Store, Autodiscovery
27 | .LINK
28 | https://ntsystems.it/PowerShell/Start-LyncBackup/
29 | .LINK
30 | http://technet.microsoft.com/en-us/library/hh202170.aspx
31 | #>
32 |
33 | #Requires -Version 3
34 |
35 | [CmdletBinding(ConfirmImpact='Medium')]
36 | Param
37 | (
38 | # PoolFqdn, specify the fully qualified domain name of the Enterprise pool or the Servername of the Standard Server.
39 | [Parameter(Mandatory=$true,
40 | Position=0)]
41 | [ValidateScript({[bool](Get-CsPool $_ -ErrorAction SilentlyContinue)})]
42 | $PoolFqdn,
43 |
44 | # Path, specify the target root folder for the backup. A new sub folder is created every time the script is executed
45 | [Parameter(Mandatory=$true,
46 | Position=1)]
47 | [ValidateScript({Test-Path $_ -PathType Container})]
48 | $Path,
49 |
50 | # Retention, specify a number of days indicating how long to keep existing backup files. Defaults to 90.
51 | [Parameter(Mandatory=$false,
52 | Position=2)]
53 | [ValidateNotNullorEmpty()]
54 | [ValidateRange(1,65535)]
55 | [int]$Retention = 90,
56 |
57 | # LogFile, specify a path to a log file. The script will log information and erros to the file.
58 | [Parameter(Mandatory=$false,
59 | Position=0)]
60 | [System.IO.FileInfo]
61 | $LogFile=(Join-Path -Path $Path -ChildPath 'log-New-SfBBackup.txt')
62 | )
63 |
64 | #region Initialize Logflie and import module
65 |
66 | Remove-Item $LogFile -ErrorAction SilentlyContinue
67 | "$(Get-Date) New-SfBBackup started" | Add-Content $LogFile -Force
68 | Write-Host "LogFile: $LogFile" -ForegroundColor Yellow
69 |
70 | try {
71 | Import-Module Lync -ErrorAction Stop
72 | } catch {
73 | "$(Get-Date) Error importing Module: $($_.ErrorRecord)" | Add-Content $LogFile
74 | exit
75 | }
76 |
77 | #endregion
78 |
79 |
80 | #region Create target directory to store the exported config files
81 |
82 | $TimeStamp = Get-Date -Format yyyy-MM-dd-hh-mm-ss
83 |
84 | try {
85 | $BackupDir = New-Item -Path $Path -ItemType Container -Name "SfBBackup-$TimeStamp" -ErrorAction Stop
86 | "$(Get-Date) Created Backup Target Directory at $($BackupDir.FullName)" | Add-Content $LogFile
87 | } catch {
88 | "$(Get-Date) Error creating Backup Target directory: $($_.ErrorRecord)" | Add-Content $LogFile
89 | exit
90 | }
91 |
92 | #endregion
93 |
94 | #region Export configuration
95 |
96 | try {
97 | Export-CsConfiguration -FileName (Join-Path -Path $BackupDir -ChildPath "CsConfiguration.zip") -ErrorAction Stop
98 | Write-Verbose "Export CS Configuration"
99 | "$(Get-Date) Export-CsConfiguration OK" | Add-Content $LogFile
100 | } catch {
101 | "$(Get-Date) Error running Export-CsConfiguration $($_.ErrorRecord)" | Add-Content $LogFile
102 | }
103 |
104 | try {
105 | Export-CsLisConfiguration -FileName (Join-Path -Path $BackupDir -ChildPath "CsLisConfiguration.zip") -ErrorVariable CsLisConfigurationError
106 | Write-Verbose "Export CS LIS Configuration"
107 | "$(Get-Date) Export-CsLisConfiguration OK" | Add-Content $LogFile
108 | } catch {
109 | "$(Get-Date) Error running Export-CsLisConfiguration $($_.ErrorRecord)" | Add-Content $LogFile
110 | }
111 |
112 | try {
113 | Export-CsUserData -PoolFQDN $PoolFqdn -FileName (Join-Path -Path $BackupDir -ChildPath "CsUserData.zip") -ErrorVariable CsUserDataError
114 | Write-Verbose "Export CS UserData"
115 | "$(Get-Date) Export-CsUserData OK" | Add-Content $LogFile
116 | } catch {
117 | "$(Get-Date) Error running Export-CsUserData $($_.ErrorRecord)" | Add-Content $LogFile
118 | }
119 |
120 | try {
121 | Export-CsRgsConfiguration -Source "ApplicationServer:$PoolFqdn" -FileName (Join-Path -Path $BackupDir -ChildPath "CsRgsConfiguration.zip") -ErrorVariable CsRgsConfigurationError
122 | Write-Verbose "Export CS RGS Configuration"
123 | "$(Get-Date) Export-CsRgsConfiguration OK" | Add-Content $LogFile
124 | } catch {
125 | "$(Get-Date) Error running Export-CsRgsConfiguration $($CsRgsConfigurationError.ErrorRecord)" | Add-Content $LogFile
126 | }
127 |
128 | #endregion
129 |
130 | #region Delete existing backups
131 |
132 | if ($Script:Error) {
133 | Write-Verbose "Encountered $($Script:Error.Count) errors, skip deleting existing files."
134 | "$(Get-Date) Encountered $($Script:Error.Count) errors, skip deleting existing files." | Add-Content $LogFile
135 | } else {
136 | Write-Verbose "No errors encountered, delete existing files."
137 | $exstingBackups = Get-ChildItem $Path -Directory -Filter "SfBBackup-*"
138 | $existingBackupsToDelete = $exstingBackups | Where-Object {$_.CreationTime -lt (Get-Date).AddDays(-$Retention)}
139 |
140 | foreach ($Backup in $existingBackupsToDelete) {
141 | try {
142 | Remove-Item -Path $Backup.FullName -Recurse -ErrorAction Stop
143 | Write-Verbose "Deleting $($Backup.FullName) "
144 | "$(Get-Date) Deleted existing backup: $($Backup.FullName)" | Add-Content $LogFile
145 | } catch {
146 | "$(Get-Date) Error deleting existing backup: $($_.ErrorRecord)" | Add-Content $LogFile
147 | }
148 | }
149 | }
150 |
151 | #endregion
152 |
153 | "$(Get-Date) New-SfBBackup ended with $($Script:Error.Count) errors." | Add-Content $LogFile
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PowerShell
2 | A repository for all kinds of scripts and snippets.
3 |
4 | # Profiles
5 | The PowerShell profile files I'm using on my Mac OSX and Windows 10 Machines.
6 | * Windows: Microsoft.PowerShell_profile.ps1
7 | * OSX: Microsoft.PowerShell_profile_osx.ps1
8 |
--------------------------------------------------------------------------------
/Read-GPG.ps1:
--------------------------------------------------------------------------------
1 | function Read-GPGMessage {
2 | <#
3 | .SYNOPSIS
4 | Invokes 'gpg' command-line tool to decrypt messages.
5 | .DESCRIPTION
6 | This cmdlet is a wrapper for 'gpg --decrypt' to read encrypted messages.
7 | .EXAMPLE
8 | PS C:\> Read-GPGMessage -Message "----BEGIN PGP...."
9 |
10 | The -Message parameter accepts a GPG encrypted string, GPG will prompt for a password and the output is written to the pipeline.
11 | .EXAMPLE
12 | PS C:\> Get-Content .\a.txt -Raw | Read-GPGMessage
13 |
14 | The -Message parameter accepts a GPG encrypted string, GPG will prompt for a password and the output is written to the pipeline.
15 | .EXAMPLE
16 | PS C:\> Read-GPGMessage -File .\a.txt -Output .\b.txt
17 |
18 | The file parameter specifies an input file that contains encrypted data, the output parameter specifies the destination file for the decrypted data.
19 | .INPUTS
20 | [string]
21 | As provided by Get-Content -Raw
22 | .OUTPUTS
23 | [string]
24 | .NOTES
25 | Author: @torggler
26 | #>
27 | [CmdletBinding(
28 | SupportsShouldProcess = $true,
29 | DefaultParameterSetName = "Message"
30 | )]
31 | param (
32 | [Parameter(
33 | Position = 0,
34 | ValueFromPipeline = $true,
35 | ParameterSetName = "Message")]
36 | [string]
37 | $Message,
38 | [Parameter(
39 | Mandatory = $true,
40 | ParameterSetName = "File")]
41 | [System.IO.FileInfo]
42 | $File,
43 | [Parameter(
44 | Mandatory = $true,
45 | ParameterSetName = "File")]
46 | [System.IO.FileInfo]
47 | $Output
48 | )
49 | process {
50 | switch ($PSBoundParameters.Keys) {
51 | "Message" {
52 | $command = " `"$message`" | gpg --decrypt"
53 | }
54 | "File" {
55 | $command = "gpg --decrypt $File"
56 | }
57 | "Output" {
58 | $command = "gpg --output $Output --decrypt $File"
59 | }
60 | }
61 | if($PSCmdlet.ShouldProcess($command, "Executing:")) {
62 | Invoke-Expression -Command $command
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/Remove-LogFile.ps1:
--------------------------------------------------------------------------------
1 | <#PSScriptInfo
2 |
3 | .VERSION 1.0.0
4 |
5 | .GUID a1ba81d3-e859-4998-b6ff-c9b8413c7316
6 |
7 | .AUTHOR @torggler
8 |
9 | .TAGS Logs
10 |
11 | .PROJECTURI https://ntsystems.it/PowerShell/Remove-LogFile/
12 |
13 | #>
14 |
15 | <#
16 | .SYNOPSIS
17 | Deletes log files.
18 | .DESCRIPTION
19 | Deletes log files, parameters can be used to specify the root folder, whether or not to include subfolders, a file extension filter and the age.
20 | This is intended to be run as scheduled task to regularly clean-up log files.
21 | .EXAMPLE
22 | PS C:\> .\Remove-LogFile.ps1 -Path C:\inetpub\logs -Age 7 -Recurse
23 |
24 | This example removes all *.log files older than 7 days from C:\inetpub\logs and any subfolders.
25 | .INPUTS
26 | None.
27 | .OUTPUTS
28 | None.
29 | .NOTES
30 | Author: Thomas Torggler; @torggler
31 | Date: 2014-04-30
32 | Version: 1.1
33 | 1.0: Basic Script
34 | 1.1: handle if no files to delete.
35 | If PowerShell Version 2.0 is used, remove the -file Parameter from Get-Childitem
36 | .LINK
37 | https://ntsystems.it/PowerShell/Remove-LogFile/
38 | #>
39 | [CmdletBinding(SupportsShouldProcess=$true)]
40 | Param
41 | (
42 | # Specify folder in which logs will be deleted
43 | [Parameter(Mandatory=$true,
44 | Position=0)]
45 | [ValidateScript({Test-Path $_ -PathType Container})]
46 | $Path,
47 |
48 | # Specify a number of days. Files with a LastWriteTime older than this will be deleted.
49 | [Parameter(Mandatory=$false,
50 | Position=1)]
51 | [ValidateNotNullorEmpty()]
52 | [ValidateRange(1,65535)]
53 | [int]$Age = 90,
54 |
55 | # Specify file extension filter. Defaults to '*.log'.
56 | [Parameter(Mandatory=$false,
57 | Position=2)]
58 | [ValidatePattern('^\*\.\w{3}$')]
59 | [string]
60 | $Filter = '*.log',
61 |
62 | # Specify a path to a log file. The script will log information and erros to the file.
63 | [Parameter(Mandatory=$false)]
64 | [System.IO.FileInfo]
65 | $LogFile="$env:temp\log-RemoveLogFile.ps1",
66 |
67 | # Include subfolders.
68 | [switch]
69 | $Recurse
70 | )
71 | # Clean and initialize Log File
72 | Remove-Item $LogFile -ErrorAction SilentlyContinue -WhatIf:$false
73 | "$(Get-Date) Remove-LogFile started!" | Add-Content $LogFile -WhatIf:$false
74 | Write-Host "LogFile: $LogFile" -ForegroundColor Yellow
75 |
76 | $filesToDelete = Get-ChildItem -Path:$Path -File -Recurse:$Recurse -Filter:$Filter | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-$Age)}
77 |
78 | if ($filesToDelete) {
79 |
80 | "$(Get-Date) Found $($filesToDelete.Count) files to delete." | Add-Content $LogFile
81 |
82 | foreach ($file in $filesToDelete) {
83 | if ($pscmdlet.ShouldProcess("$($File.FullName)", "Delete"))
84 | {
85 | Remove-Item -Path $file.FullName
86 | "$(Get-Date) Removed $($file.FullName)" | Add-Content $LogFile
87 | }
88 | }
89 | } else {
90 | "$(Get-Date) Nothing to delete." | Add-Content $LogFile -WhatIf:$false
91 | }
92 |
93 | "$(Get-Date) Remove-LogFile ended!" | Add-Content $LogFile -WhatIf:$false
--------------------------------------------------------------------------------
/Restore-VMPermission.ps1:
--------------------------------------------------------------------------------
1 | <#PSScriptInfo
2 |
3 | .VERSION 1.0.1
4 |
5 | .GUID c5fdb6c5-a3d3-4d1b-90e6-9c878dbae95b
6 |
7 | .AUTHOR @torggler
8 |
9 | .PROJECTURI http://www.ntsystems.it/page/PS-Restore-VMPermissionps1.aspx
10 |
11 | .EXTERNALMODULEDEPENDENCIES Hyper-V
12 |
13 | #>
14 |
15 | <#
16 | .Synopsis
17 | Adds permissions for the VMId to all assigned disks.
18 | .DESCRIPTION
19 | This script uses the Hyper-V Module to update permissions for all assigned disks on one ore more VMs.
20 | This is useful if you move/replace VHDs and the read permission for VMId is missing.
21 | .INPUTS
22 | You can pipe objcets with a VMName property, such as returned by Get-VM, to this script.
23 | .OUTPUTS
24 | None. This script does not write any objects to the pipeline.
25 | .EXAMPLE
26 | Restore-VMPermission.ps1 -VM dc01
27 |
28 | This example adds permission for dc01 VMId to the ACL of all assigned disks for dc01.
29 | .EXAMPLE
30 | Get-VM | Restore-VMPermission.ps1
31 |
32 | This example uses Get-VM to get all VMs on the local machine. It gets all disks for all VMs and adds the required premissions for VMId to the ACL.
33 | .ROLE
34 | Get-VM requires administrative rights.
35 | .LINK
36 | https://ntsystems.it/PowerShell/Restore-VMPermission
37 | #>
38 |
39 | [CmdletBinding(ConfirmImpact='Medium',SupportsShouldProcess=$true)]
40 | Param
41 | (
42 | # VM, specify the VM that needs permissions fixed.
43 | [Parameter(Mandatory=$true,
44 | ValueFromPipelineByPropertyName=$true,
45 | Position=0,
46 | ParameterSetName='Parameter Set 1')]
47 | [ValidateNotNull()]
48 | [ValidateNotNullOrEmpty()]
49 | [Alias("VMName")]
50 | [Alias("Name")]
51 | [string[]]
52 | $VM
53 | )
54 |
55 | begin {
56 |
57 | try {
58 | Import-Module Hyper-V -ErrorAction Stop -Verbose:$false
59 | } catch {
60 | Write-Warning -Message "$(Get-Date) Error importing Lync Module: $($_.ErrorRecord)"
61 | exit
62 | }
63 |
64 | } # end Begin
65 |
66 | process {
67 |
68 | try {
69 | Write-Verbose 'Trying to get VM'
70 | $VirtualMachines = Get-Vm $VM -ErrorAction Stop -ErrorVariable GetVmError
71 | }
72 | catch {
73 | Write-Warning -Message "Could get VM: $($GetVmError.ErrorRecord)"
74 | }
75 |
76 | foreach ($VirtualMachine in $VirtualMachines) {
77 |
78 | Write-Verbose "Processing VM: $($VirtualMachine.Name)"
79 |
80 | $colRights = [System.Security.AccessControl.FileSystemRights]"Read, Write, Synchronize"
81 | $InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]::None
82 | $PropagationFlag = [System.Security.AccessControl.PropagationFlags]::None
83 | $objType =[System.Security.AccessControl.AccessControlType]::Allow
84 | $objUser = New-Object System.Security.Principal.NTAccount("NT VIRTUAL MACHINE\$($VirtualMachine.VMId)")
85 | $objACE = New-Object System.Security.AccessControl.FileSystemAccessRule ($objUser, $colRights, $InheritanceFlag, $PropagationFlag, $objType)
86 |
87 | foreach ($Disk in $VirtualMachine.HardDrives) {
88 | Write-Verbose "Processing VM $($VirtualMachines.Name) controller: $($Disk.ControllerNumber) disk: $($Disk.ControllerLocation)"
89 | $objACL = Get-ACL -Path $Disk.Path
90 | $objACL.AddAccessRule($objACE)
91 |
92 | if ($pscmdlet.ShouldProcess("$($Disk.Path)", "Adding permission for $objUser")) {
93 | Set-ACL -Path $Disk.path -AclObject $objACL
94 | }
95 | } # end foreach
96 | } # end foreach
97 | } # end Process
--------------------------------------------------------------------------------
/Restore-VmPermission.Tests.ps1:
--------------------------------------------------------------------------------
1 |
2 | # Define variables for Mock runs
3 | $global:mockedVM = [pscustomobject] @{
4 | Name = "My VM 01"
5 | VmId = (New-Guid).ToString()
6 | HardDrives = @{
7 | ControllerNumber = 0
8 | ControllerLocation = 0
9 | Path = "myvhd.vhd"
10 | }
11 | }
12 |
13 | # Testing with mocked commands
14 | Describe "Testing Restore-VmPermission" {
15 |
16 | Mock Get-VM -MockWith {return $global:mockedVM} -verifiable
17 |
18 | $VhdPath = Join-Path -Path $TestDrive -ChildPath "myvhd.vhd"
19 |
20 | Context "Testing Prerequisites" {
21 | It "Test Hyper-V PowerShell module" {
22 | $module = Get-Module -Name Hyper-V -ListAvailable -ErrorAction SilentlyContinue
23 | $module -is [PSModuleInfo] | Should be $true
24 | }
25 | It "Test Get-VM Connectivity" {
26 | $vm = Get-VM
27 | $vm | Should Not Be $null
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/Send-MailJetMail.ps1:
--------------------------------------------------------------------------------
1 | function Send-MailJetMail {
2 | [cmdletbinding()]
3 | param(
4 | [string]$Sender,
5 | [string]$Recipient,
6 | [string]$Subject,
7 | [string]$Text,
8 | [string]$User,
9 | [string]$Key
10 | )
11 |
12 | $body = [ordered]@{
13 | Messages= @(@{
14 | to = @(@{email = $recipient})
15 | from = @{email = $Sender ; name = "notification"}
16 | subject = $Subject
17 | TextPart = $Text
18 | })
19 | }
20 |
21 | $userkey = $user,$key -join ":"
22 | $auth = $userkey | ConvertTo-Base64
23 | $param = @{
24 | Uri = "https://api.mailjet.com/v3.1/send"
25 | ContentType = "application/json"
26 | body = ($body | ConvertTo-Json -Depth 4 -Compress)
27 | Method = "POST"
28 | Headers = @{Authorization=("Basic $auth")}
29 | UseBasicParsing = [switch]::Present
30 | }
31 | $Result = Invoke-RestMethod @param
32 | if($Result) {
33 | $Result.Messages
34 | }
35 | }
--------------------------------------------------------------------------------
/Send-SplunkEvent.ps1:
--------------------------------------------------------------------------------
1 | <#PSScriptInfo
2 |
3 | .VERSION 1.0.1
4 |
5 | .GUID a7d9b0b5-0f81-4ec7-be89-7c6a0390ef50
6 |
7 | .AUTHOR @torggler
8 |
9 | .TAGS Splunk
10 |
11 | .PROJECTURI https://ntsystems.it/post/sending-events-to-splunks-http-event-collector-with-powershell
12 |
13 | #>
14 |
15 | <#
16 | .SYNOPSIS
17 | Send events to Splunk's HTTP Event Collector.
18 | .DESCRIPTION
19 | This function uses Invoke-RestMethod to send structured data to Splunk HTTP Event Collector. Use the
20 | HostName and DateTime parameters to control Splunk's 'host' and 'time' properties for the generated event.
21 | .EXAMPLE
22 | PS C:\> .\Send-SplunkEvent.ps1 -InputObject @{message="Hello Splunk!"} -Key