PSSDIAG Files
===============Confirm-FileAttributes.ps1======================
## Copyright (c) Microsoft Corporation.
## Licensed under the MIT license. [CmdletBinding()] param ( [Parameter(Mandatory=$false)] [bool] $debug_on = $false ) function Confirm-FileAttributes { <# .SYNOPSIS Checks the file attributes against the expected attributes in $expectedFileAttributes array. .DESCRIPTION Goal is to make sure that non-Powershell scripts were not inadvertently changed. Currently checks for changes to file size and hash. Will return $false if any attribute mismatch is found. .EXAMPLE $ret = Confirm-FileAttributes #> if ($debug_on -eq $true) { $DebugPreference = "Continue" } Write-Host "Validating attributes for non-Powershell script files" # TODO: deal with ManualStart, ManualStop and pssdiag_xevent.sql $validAttributes = $true #this will be set to $false if any mismatch is found, then returned to caller $expectedFileAttributes = @( [PSCustomObject]@{Algorithm = "SHA512"; Hash = "6AFC48EB276028FFC902B7856C19CA0C08ABB912E1EF9AAD81018E04D24DBDBD958E03ED3B588786332F5DFE239DFA237030372B204CBF60650B051EB277970C"; FileName = ".\AlwaysOnDiagScript.sql"; FileSize = 19874} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "C0D633F8AA0C7FAE10AB0E596DD710E2CBC673A4BFE93F124B14002E8F65F116DCDCC9CB94EA7CFCF7DBABC071947382DED4592C535FE6B9C00FC34A1D091599"; FileName = ".\AlwaysOnGetClusterLogs.cmd"; FileSize = 138} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "55B8B497973F9C0980C696A0599ECAF3401C4A02FBEBFDC78608CA3354AE01E1EA03508FB558AA4548EA74988C1BA9E5DFAE310F6D60A23B38D39B310A9A84A6"; FileName = ".\AutoUserDump.bat"; FileSize = 2829} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "41938EE0E0ADE87E0D26F88C28F8A70CC54D0AE8CA21657AD5F72918E364F4C3972F1C6C86267A79D39C2D418BF89A60AE2EA2EF9998084DFEA85F9DC8D61478"; FileName = ".\build.cmd"; FileSize = 609} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "4E2E0C0018B1AE4E6402D5D985B71E03E8AECBB9DA3145E63758343AEAC234E3D4988739CCE1AC034DDA7CE77482B27FB5C2A7A4E266E9C283F90593A1B562A2"; FileName = ".\ChangeDataCapture.sql"; FileSize = 4672} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "72B955257DD659BC09EDF3621F90BA2731BE817F02972F2AFBDE0BB374AFA43FA582C72B7A6562A2C4950F435FCD7019D5DC354449CD4667F33D55763007694F"; FileName = ".\Change_Tracking.sql"; FileSize = 5112} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "BF6CF04DB43D9C41E34C12A81DFB6DE7D9187BA2EC89EF0AC5AE8BB842CD00EC1FBDCB7870249AE5F2A9950FE0FD85A3BE6275856504F49BF578A9693E49063C"; FileName = ".\CMemthread.sql"; FileSize = 461} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "75B822DAAED573CEC075EC39AF882FED3340B8809235AAB5DBFB5673008474DA8EF2B57ECC5F563668F8F526E24B22555B33F0D5167F5B83D7E16D41271F307A"; FileName = ".\collecterrorlog.cmd"; FileSize = 263} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "BC7120451387E14695D1E6AAC25783C2C7299A131672D0BB28CB6971DEE53DF23D82E6A5D2E63D20DCC0EEE8BB26A8D3E93B2EFF7E400641FA959BE829B9FFFD"; FileName = ".\collecterrorlog.sql"; FileSize = 361} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "F5AB1122719AC332E9359A3A4884BF6FA922383236858A0884EF6D9CEBD80ED2151AF7E95A9C4B6019C2A55A0A987037E16FD0443E7E487385502863C3A0A0E8"; FileName = ".\ColumnStore.sql"; FileSize = 4970} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "AEBBAB953A7187281EBCAE85FC38F3FCDBA600220FDFC3A29348626B394D2FC4E938065F1EF3375EB91A962F31572704E72814D76DB8264C35FFF01D55049BA2"; FileName = ".\ConnectivityTest.bat"; FileSize = 3746} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "7E794E2322F58933E8769FB680F3B232B3287EFAB71FF2D709273704BD578866E5A640FEBB935B9170570136C49905B52CD7BB7D4986D92D280B40B7F2F27C64"; FileName = ".\DefineCommonVars.cmd"; FileSize = 4321} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "99F853F56BD0253176F12678D25D1F564E3BD5C8E1432E669E3AF6126DD3169CAF2ECB6D3B03B08E65934B8BDD694B6C9708076FDFE003C293BA7346C8D58C3E"; FileName = ".\DefineSQLInstanceSetupPaths.cmd"; FileSize = 2410} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "FC627ABB404C01F9E1EF8A533F8D607B1FFF22D94E4E89D2A124B396F572724B9004D1B3B52240E6D2B1917FD9A0519189E88688BC72575462143975AC6134FF"; FileName = ".\errorlogs.js"; FileSize = 7731} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "EFC59387B7510BD7C79870C94A7DCB25D11FB04421D07B7C570ED809C85ADD64E0DC4A1FD3D6317106A837DBCAC3B1A15362D7F90AF45173E0D852C3F2D05350"; FileName = ".\FTS_Collector.sql"; FileSize = 13855} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "F539B33196C4BC259E2F9983D31F05DEAC93BC23794197A9580F9BC9E15F0274E5CC4673E36E04495ABF3A59CF78792489DE1537AEFB738DF179B745B8B43555"; FileName = ".\fts_info.sql"; FileSize = 5846} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "216681E0F3541DAD01652B4D319B3C6619EAC8684F33694F52DC3DC509B0D80D7E1B7F121642A0C275D60F1581B00089D0AD01A713745EEC3F0FFAA1A38EB3D4"; FileName = ".\GetAllSQLInstancePIDS.cmd"; FileSize = 734} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "96A70F624E21EAA4118AC10EE2D0168F6F4369886B218571237EFF9063A1C1FAAB749B4FDD57DFAD411262981C23540EE7CCD2906ED44C2E4F1664F282F4D193"; FileName = ".\GetFileVer.CMD"; FileSize = 1317} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "1A3BD5E09DAFCAD9F70BB0128007BD0BAF5CDD6916DA7A4F9815F8D92674D9EFA4252654B20AEE5CFAC3BAEABFB80DD03AC39FD4B11975B2D81174D289DA27DD"; FileName = ".\GetRegValue.CMD"; FileSize = 1117} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "7D890D6E26FD93676CDC7C5525D0D2F35BA1FEB8A0C2344C157922668798734907C5EC046B40F7DB1440E90E26406036B2AA44582F17B35B1789E122F323C30B"; FileName = ".\GetSQLInstancePID.CMD"; FileSize = 2118} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "9E6A3A9EDBBCDE9DA84D7635396977B6FEF6512A51A9A396004A6EFF67CEF4C99EE61CBD9CCE1776B55CD78442F1CA3300A99E170CBF3F99410364B45932DF9E"; FileName = ".\get_dbccloginfo.sql"; FileSize = 494} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "45B6F82A7993AABE6C1CB1ACE51F21EEA68CFB624F101F3E0604E41E20FCAAE48D50FC18EF165CC46F8C6450E6182C9101294550527DD5679A905E5D1E42E991"; FileName = ".\get_dbmirroringinfo.sql"; FileSize = 5138} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "FF0BE2ACCF32E5557C70774E480B48266355D928CDE07E1A265459D1FB660C86531AE354F5379263F99EDEBD4F4C1D37D0BED7919F3D92D19B65344432A9BBC7"; FileName = ".\get_dbmirroringinfo.vbs"; FileSize = 2556} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "A81FF0564F8D79674C36461D86E4338C0C28C7995CDEEE970107DD8FB3915ABC68380A1BCB01EFD8A839F26BCD271880118F6E0447972D37834DB0EB4C690CC8"; FileName = ".\get_tasklist.cmd"; FileSize = 373} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "46D03FC5E13114C1DA826DB266EA5A5219E15510709EBEC416D9F30858325FE0F5E6AD94247431A34E8AAD09B62B15919FB3058F2B68D868703CF959ADC707DA"; FileName = ".\HighCPU_perfstats.sql"; FileSize = 5334} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "BA125F5D7F76C0B6D70A8B198532EE9DE6B179DAFECBC2D5AFE256DA569900CC483381EB1D717817FB7AB5AEF6DD8C30FD8A73819BA3B870C5838FDE37E9659E"; FileName = ".\In_Memory_OLTP.sql"; FileSize = 2273} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "804B3E27309C23E9530BF475DBD8DA52D1DFA334D7A118DE66B77E4E8182BA8FAC1F938C2FDC1D4CB11F73295354ADEECC33075BF7B87F2C505C03C1BB8E86FB"; FileName = ".\linked_server_config.sql"; FileSize = 3638} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "78CDEFB86A57A39A551DD8D7D38028AF6B8073C4175731AD014F9E90F136C5E0AFD0074C19CA4048492EFF5297867FF663531C90C3B012D0078561BCFD5F4177"; FileName = ".\ManualStart.cmd"; FileSize = 4015} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "7698E15AC47A1735C1C6D630CC4A451F13F80D3B3F578BA0802CDAD43DB224D78E9498B28B40FB929B12FCEB7129560565FC4AADBEE888863E268BC73B378AD0"; FileName = ".\ManualStop.cmd"; FileSize = 1727} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "CD1564EB4C7A1A404C2C6AD67417502257584F91BB57603E0A8B9940E3090252F9C8723454CB052803D911C9B084A6058993B2032BE9E9DCE906072C329743EA"; FileName = ".\ManualUserDump.bat"; FileSize = 1220} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "E5767D07D745ABEE75D3642C95EE3D89B56EFB1537DCC3B700FE16156E63614DCB9DF81DFB0028670488EFD362B1E66E13812E85F2E4E6973D0FD2CF95A823AB"; FileName = ".\MiscPssdiagInfo.sql"; FileSize = 14964} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "EB35C41EB301CED435EDEAD31CC6E23EB8B04EB7BDFC1A805CFA835B3D194DEF8FD7F111AF971122937FAF0AC1EF42B2CFA4CBC79EFAE4CB0438C91396F14F58"; FileName = ".\MSDiagProcs.sql"; FileSize = 191478} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "8366A86E01D3430AF1DF9E51A852324A64D5D63DAD3E68EF6AF240E29FAA8A397CF06390A05AB4CFF97FF3B65A825FAFA11381D2D10045AAE344FE1BEFE90A33"; FileName = ".\My Collector Script.sql"; FileSize = 47} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "0DA7B5F39B23196B16913AB660099B82F384E1C1757FF524894A37867010965E7E28ED87D87DAB00632482D12417DB9D21F1B52B4A8D8750192CECF39E57A448"; FileName = ".\OutputActiveTimeBias.CMD"; FileSize = 719} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "5CF137CA8F4C34DAD59D1C21D41F1C13D4AA933B7AB593272D4C785EE3F087689BEB9FBA0D163DD21AF2F4C68C574B5C3D33979ACE92E9D747503A1490671A9A"; FileName = ".\PolyBase.sql"; FileSize = 1959} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "782D8FFD9E46AAEA7ED70A608A2BAD37E1FAB7DDF6A8FF6423A365B69F0CC2DEBA753EF1E0C897412B6C115DC23A472320AF1465AFE702E1ED91C8123CA1E36C"; FileName = ".\PowerPlan.VBS"; FileSize = 650} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "2E209F7D1ECA92396A620FB0B92DED937EBFF1F59A017B47A27672A151C4F32E8189CF1AB66E082946219AAEA091B6EF0D712C1D6080A19006702273D60957D2"; FileName = ".\Profiler Traces.sql"; FileSize = 2743} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "825C5281C6D1654A2E557814F751E7A50F6F525E9CF3529E4F1EDBE0FB68E42DC80517CD297CDE658540A6383EE54A2A5239ADFA994175274F8D96861C9F4DDB"; FileName = ".\Query Store.sql"; FileSize = 2589} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "6707EEE5E26A79C22AB0387B900EF4014599D33244E1E19CCB85206D58B26A659BE8E7585BCCC30FC7CB5E92C1348A30E94A8EC72DF04AEEDDB5E641DCF2DCE0"; FileName = ".\QueryNeverCompletes_perfstats.sql"; FileSize = 6854} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "4B7745C8EEB9BFE49AD89B481591F3FAA1FAC8B1D6909A8C43C091CED79F609E57274284CB23FADB14447979AC11A0427F379E1D509D7CA33BADF0F9D42F52CB"; FileName = ".\Repl_Metadata_Collector.sql"; FileSize = 50941} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "902A5292AF20AD580AD196828C7EAA0E97E35308E919A4E1999F92C6486A09147690FF493752316613EDE36E41ACE5D743D9D52E69C4D678FEE1D6E03C11A4B9"; FileName = ".\rtrim.vbs"; FileSize = 423} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "15C8D2F26416FFA1C0A913A2E22A4448CB1E777D3EA7558F4E58C83C7462A2069BEA6AE687C741D89059DBB98C52FA30E900324EC9D98261A13E1DFE083A19C7"; FileName = ".\run_in_dir.cmd"; FileSize = 49} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "0E5EDDED466F2AE758E7B1CE1A9C66952F29251BB3B980145688A969B76711AFAE60528E2B9942E43BA268A5D50BCADD88FBE354184C47F6D456FDAE50DFB9A0"; FileName = ".\SetSqlEnvVariables.cmd"; FileSize = 1008} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "AE3BFFB70FAC3DCCFA61192DF515635832D819545B84F915AF63378C33422E8FCAC23BEA128B91907F420E46524321866904C24CCA6A352B85E9519CB2A35EDD"; FileName = ".\SetupVars.bat"; FileSize = 1126} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "586CD47C9668C7FF3412D3FD8F5AC56F2E7AC386A53404E4002DD3CD7C1B4B0354500C4973A1C8296E3C932DF62D6641B52EA1C13E4674BB6299FD7B390A642F"; FileName = ".\SQL Server Perf Stats Snapshot.sql"; FileSize = 34914} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "7D6A02F371BC1F4043998EDFF1E252B74DDA1B7435A649E74CFD2E41C1BFA5630508D06FD68BC432008137A82DCA0DF0B45D2127C3A66736DA5E4C4CDD0463C8"; FileName = ".\SQL Server Perf Stats.sql"; FileSize = 71410} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "46BD5A2066A43B03816FAE181C9ECB8653E24C6542F391A3FF74E503C5A0D8485EC0EB8CBAE941D8FF028B7F5DB7124325547F94EDCE566E9486E36149DD1924"; FileName = ".\SQL_Server_Mem_Stats.sql"; FileSize = 16909} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "5CB4E3F3B3FD99E90603D84AD8C18C6A06E663210C2FD6FB42718431CACB7F84E5DFA3B172C1E065F70504B415D4EE9AAB2CFE0333A9CD28381D73E39C77A781"; FileName = ".\SSB_pssdiag.sql"; FileSize = 10531} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "D5DB0DC73327FAA34A67DFC7EFFED7A740994AFACE122DEAC2F3905F52747FFF1D1DB83518EA3F7DC937A045A6E5EA5DC947C6E00BE0591640371B88B5ED7DA7"; FileName = ".\StartFromPSSDiag.bat"; FileSize = 1607} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "93C312346BD00C02B7241813397C9B99F9400BB2ADF31077E5B4BA1FF7ABAE656490AF3D049B3F2D621D93C972157F860E5C2BCF4D7EC4A52904B4EACD7FF6D3"; FileName = ".\StartPSS.bat"; FileSize = 310} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "ABA1A57AB4E5FAA9D3D783C29AFBB74E874A58E50A2889661F7CA57EACC9FB4A9B4D7182B069A4DBE815E951370E7BAC78FDB2A2D0D601458A2A2C7B970A2E06"; FileName = ".\StretchDB.sql"; FileSize = 29} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "A5AB03D93D7FB256C2DC08B9E5C46CF7D71C403F3074564A66E37DF46F75396BE69593DA2ECA2480073608C5FF215EDE36C6571155BD7EF6B2282C7888EF9401"; FileName = ".\TempDB_and_Tran_Analysis.sql"; FileSize = 9054} ,[PSCustomObject]@{Algorithm = "SHA512"; Hash = "81EB149D0182A4E7FD62007B69A3658E1126F9723DB386BD358CA7CAC695431AFB2684D4A40D7F7A4E07F2FB727B4F904507CC6E0A6F03B5BBE9323AB0F60681"; FileName = ".\TopCPUQueryShowPlanXML.bat"; FileSize = 883} ) # global array to keep a System.IO.FileStream object for each of the non-Powershell files # files are opened with Read sharing before being hashed # files are kept opened until SQL LogScout terminates preventing changes to them #[System.Collections.ArrayList]$Global:hashedFiles = [System.Collections.ArrayList]::new() $Global:hashedFiles = New-Object -TypeName System.Collections.ArrayList foreach ($efa in $expectedFileAttributes) { try { Write-Debug ("Attempting to open file with read sharing: " + $efa.FileName) $cur_file = $efa.FileName if ((Test-Path -Path $cur_file) -eq $true) { $cur_file = Convert-Path -Path $cur_file $fstream = [System.IO.File]::Open($cur_file, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read) Write-Debug ("FileName opened = " + $fstream.Name) } else { Write-Debug ("File " + $efa.FileName + " not present") Continue } # open the file with read sharing and add to array [void]$Global:hashedFiles.Add($fstream) } catch { $validAttributes = $false Write-Host ("Error opening file with read sharing: " + $efa.FileName ) -ForegroundColor Red Write-Host $_ -ForegroundColor Red return $validAttributes } Write-Debug ("Validating attributes for file " + $efa.FileName) try { $file = Get-ChildItem -Path $efa.FileName if ($null -eq $file){ throw "`$file is `$null" } } catch { $validAttributes = $false Write-Host "" -ForegroundColor Red Write-Host ("Could not get properties from file " + $efa.FileName) -ForegroundColor Red Write-Host $_ -ForegroundColor Red Write-Host "" -ForegroundColor Red return $validAttributes } try { $fileHash = Get-FileHash -Algorithm $efa.Algorithm -Path $efa.FileName if ($null -eq $fileHash){ throw "`$fileHash is `$null" } } catch { $validAttributes = $false Write-Host "" -ForegroundColor Red Write-Host ("Could not get hash from file " + $efa.FileName) -ForegroundColor Red Write-Host $_ -ForegroundColor Red Write-Host "" -ForegroundColor Red return $validAttributes } if(($file.Length -ne $efa.FileSize) -or ($fileHash.Hash -ne $efa.Hash)) { $validAttributes = $false Write-Host "" -ForegroundColor Red Write-Host ("Attribute mismatch for file: " + $efa.FileName) -ForegroundColor Red Write-Host "" -ForegroundColor Red Write-Host ("Expected File Size: " + $efa.FileSize) -ForegroundColor Red Write-Host ("Actual File Size: " + $file.Length) -ForegroundColor Red Write-Host "" -ForegroundColor Red Write-Host ("Expected Hash: `n" + $efa.Hash) -ForegroundColor Red Write-Host ("Actual Hash: `n" + $fileHash.Hash) -ForegroundColor Red Write-Host "" -ForegroundColor Red } else { Write-Debug ("Actual File Size matches Expected File Size: " + $efa.FileSize + " bytes") Write-Debug ("Actual Hash matches Expected Hash (" + $efa.Algorithm + "): " + $efa.Hash ) } if (-not($validAttributes)){ # we found a file with mismatching attributes, therefore backout indicating failure return $validAttributes } $fstream.Close() $fstream.Dispose() } #foreach return $validAttributes } # use to calculate filehash values when files are changed function Get-FileAttributes([string] $file_name = ""){ <# .SYNOPSIS Display string for $expectedFileAttributes. .DESCRIPTION This is to be used only when some script is changed and we need to refresh the file attributes in Confirm-FileAttributes.ps1 .EXAMPLE . .\Confirm-FileAttributes.ps1 Get-FileAttributes #> [int]$fileCount = 0 [System.Text.StringBuilder]$sb = New-Object -TypeName System.Text.StringBuilder [void]$sb.AppendLine("`$expectedFileAttributes = @(") foreach($file in (Get-ChildItem -Path . -File -Filter $file_name)){ # Powershell files are signed, therefore no need to hash-compare them # "Get-ChildItem -Exclude *.ps1 -File" yields zero results, therefore we skip .PS1 files with the following IF if (".ps1" -ne $file.Extension){ $fileCount++ # append TAB+space for first file (identation) # append TAB+comma for 2nd file onwards if($fileCount -gt 1){ [void]$sb.Append("`t,") } else { [void]$sb.Append("`t ") } $fileHash = Get-FileHash -Algorithm SHA512 -Path $file.FullName $algorithm = $fileHash.Algorithm $hash = $fileHash.Hash $fileName = ".\" + $file.Name $fileSize = [string]$file.Length [void]$sb.AppendLine("[PSCustomObject]@{Algorithm = `"$algorithm`"; Hash = `"$hash`"; FileName = `"$fileName`"; FileSize = $fileSize}") } } [void]$sb.AppendLine(")") Write-Host $sb.ToString() }
=================================Multicopy.ps1========================================
param(
[Parameter(Position=0)]
[string]$sourcePath,
[Parameter(Position=1)]
[string]$destinationPath,
[Parameter(Position=2)]
[string]$serverName
)
if ($serverName -Like '*\*')
{
$serverName = $serverName -replace"\\","_"
}
Get-ChildItem $sourcePath -FILE | ForEach-Object {
If ([String]::IsNullOrEmpty($serverName))
{
$newFileName = $_.Name
}
else
{
$newfileName = $serverName + "_" + $_.Name
}
$newfileName = Join-path $destinationPath $newfileName
Try {
Copy-Item -Path $_.FullName -Destination $newFileName -ErrorAction Stop
}
Catch {
Write-Output $_.Exception.Message
}
}
=================================SetSqlEnvVariables.cmd==================================
set MACHINENAME=%1 set INSTANCENAME=%2 set SSVER=%3 echo MACHINENAME: %MACHINENAME% echo INSTANCENAME: %INSTANCENAME% echo SSVER: %SSVER% set SQLGLOBAL_VERSION=130 if "%SSVER%"=="10.50" ( set SQLGLOBAL_VERSION=110 ) else ( set SQLGLOBAL_VERSION=%SSVER%0 ) echo SQLGLOBAL_VERSION: %SQLGLOBAL_VERSION% @echo off rem getting tools root dir set KEY_NAME=HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\%SQLGLOBAL_VERSION% set VALUE_NAME=VerSpecificRootDir FOR /F "skip=2 tokens=1,2*" %%A IN ('REG QUERY "%KEY_NAME%" /v "%VALUE_NAME%" 2^>nul') DO ( set ValueName=%%A set ValueType=%%B set ValueValue=%%C ) if defined ValueName ( echo Value Name = %ValueName% echo Value Type = %ValueType% echo Value Value = %ValueValue% ) else ( @echo "%KEY_NAME%"\"%VALUE_NAME%" not found. ) set SQLTOOLSROOT=%ValueValue% echo SQLTOOLSROOT:%SQLTOOLSROOT% set SQLDUMPERPATH=%SQLTOOLSROOT%shared echo SQLDUMPERPATH: %SQLDUMPERPATH%
=====================================perfmon_translate.ps1===============================
#Check if the language is not English if(((Get-WinUserLanguageList).LanguageTag | Select -First 1) -notlike "en*"){ Write-Host "$(Get-Date -Format "MM/dd/yyyy HH:mm:ss.fff") Executing:Perfmon Counters localization. Please wait..." #Get all Local existing counters paths in array for future check $counterexistingpaths = @(Get-Counter -ListSet *).Paths $countertranslatedcounters = 1 #Get performance counters names and ID's in english and local languages to hash table $pc_en_names = [Microsoft.Win32.Registry]::PerformanceData.GetValue("Counter 009") $pc_en_hash = @{} $duplicated_en_names_pc_hash = @{} foreach ($item in $pc_en_names) { $pc_id_indexnumber = $pc_en_names.IndexOf($item) $pc_name_indexnumber = $pc_id_indexnumber+1 $pv_name_to_add = $pc_en_names[$pc_name_indexnumber] if($pc_id_indexnumber% 2 -eq 0 ) { #check IF Hash Key already exist if(-not ([string]::IsNullOrEmpty($pv_name_to_add)) -and $pc_en_hash.ContainsKey($pv_name_to_add)) { $existing_name = $pc_en_hash.$pv_name_to_add $duplicated_en_names_pc_hash["$existing_name"] = $pv_name_to_add $duplicated_en_names_pc_hash["$item"] = $pv_name_to_add } $pc_en_hash["$pv_name_to_add"] = $item } } $pc_local_names = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage' -Name 'counter').Counter $pc_local_hash = @{} foreach ($item in $pc_local_names) { $pc_id_indexnumber = $pc_local_names.IndexOf($item) $pc_name_indexnumber = $pc_id_indexnumber+1 if($pc_id_indexnumber% 2 -eq 0 ) { #Write-Host "$($pc_id_indexnumber) is even and the name is $($pc_en_names[$pc_name_indexnumber])" $pc_local_hash["$item"] = $pc_local_names[$pc_name_indexnumber] } } #get pssdiag xml with performance counters info $pathxml = "pssdiag.xml" $xml = [xml](Get-Content $pathxml) #Get all Perfmon Objects $obnodes = $xml.dsConfig.Collection.Machines.Machine.MachineCollectors.PerfmonCollector.PerfmonCounters.SelectNodes("//PerfmonObject[@name]") #Translate each Object foreach ($obnode in $obnodes) { #find performance object in XML $xmlPerfObejct = $xml.dsConfig.Collection.Machines.Machine.MachineCollectors.PerfmonCollector.PerfmonCounters.SelectSingleNode("//PerfmonObject[@name='" + $obnode.name + "']") #split the string before and after the (), add the first parenteses after split IF($xmlPerfObejct.name.Contains("(")) { $afixo = $xmlPerfObejct.name.Split('(') $afixo[1] = '(' + $afixo[1] }ELSE{ $afixo[0] = $xmlPerfObejct.name $afixo[1] = "" } #Remove the \ at the beginning of the performance object name and make sure exact match name search $searchOBname= $afixo[0].substring(1) #Get the Object ID based on the line before of the name match $LocalPerfObID = $pc_en_hash.$searchOBname IF (-not ([string]::IsNullOrEmpty($LocalPerfObID))){ $pob_local_name = $pc_local_hash."$LocalPerfObID" IF (-not ([string]::IsNullOrEmpty($pob_local_name))){ $pob_translated_name = "\" + $pob_local_name + $afixo[1] #change the xml of the counter $xmlPerfObejct.name = $pob_translated_name } } #Get Perfmon Counters per perfmonobject $pcnodes = $xml.dsConfig.Collection.Machines.Machine.MachineCollectors.PerfmonCollector.PerfmonCounters.SelectNodes("//PerfmonObject[@name='" + $obnode.name + "']/PerfmonCounter[@name]") foreach ($pcnode in $pcnodes) { #find performance object in XML $xmlPerfCounter = $xml.dsConfig.Collection.Machines.Machine.MachineCollectors.PerfmonCollector.PerfmonCounters.SelectSingleNode("//PerfmonObject[@name='" + $obnode.name + "']/PerfmonCounter[@name='" + $pcnode.name + "']") IF ($xmlPerfCounter.name -ne "\(*)"){ #Remove the \ at the beginning of the performance object name and make sure exact match name search $searchpcname= $xmlPerfCounter.name.substring(1) #Get the Object ID based on the line before of the name match $LocalPerfCounterID = $pc_en_hash.$searchpcname IF (-not ([string]::IsNullOrEmpty($LocalPerfCounterID))){ $pc_local_name = $pc_local_hash."$LocalPerfCounterID" IF (-not ([string]::IsNullOrEmpty($pc_local_name))){ #Confirm correct name translation per object+countername IF ($duplicated_en_names_pc_hash.ContainsKey($LocalPerfCounterID)){ $pc_duplicated_id = $duplicated_en_names_pc_hash.Keys.Where({$duplicated_en_names_pc_hash[$_] -eq $searchpcname}) foreach ($dup_node in $pc_duplicated_id){ $dup_node_name = $pc_local_hash."$dup_node" $confirm_counter = $pob_translated_name + "\" + $dup_node_name IF ($counterexistingpaths.Contains($confirm_counter)){ $pc_local_name = $dup_node_name } } } $pc_translated_name = "\" + $pc_local_name #change the xml of the counter $xmlPerfCounter.name = $pc_translated_name $countertranslatedcounters = $countertranslatedcounters +1 } } } } } #save the XML file with the changes $xmlsavelocation = (Get-Location).Path + "\" + $pathxml $xml.Save($xmlsavelocation) Write-Host "$(Get-Date -Format "MM/dd/yyyy HH:mm:ss.fff") $countertranslatedcounters Perfmon counters in local Language saved in pssdiag.xml"}
====================================pssdiag.ps1======================
param ( [Parameter(ParameterSetName = 'ServiceRelated',Mandatory=$true)] [Parameter(Position = 0)] [string] $ServiceState = "", [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [switch] $help, [Parameter(ParameterSetName = 'Config',HelpMessage='/I xml_config_file',Mandatory=$false)] [string] $I = "pssdiag.xml", [Parameter(ParameterSetName = 'Config',HelpMessage='/O output_path',Mandatory=$false)] [string] $O = "output", [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [string] $P = "", [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [string] $N = "1", [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [string] $M = [string]::Empty, [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [switch] $Q , [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [string] $C = "0", [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [switch] $G, [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [switch] $R, [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [switch] $U, [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [string] $A = [string]::Empty, [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [switch] $L, [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [switch] $X, [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [string] $B = [string]::Empty, [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [string] $E = [string]::Empty, [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [string] $T = [string]::Empty, [Parameter(ParameterSetName = 'Config',Mandatory=$false)] [switch] $DebugOn ) . ./Confirm-FileAttributes.ps1 function Check-ElevatedAccess { try { #check for administrator rights if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Warning "$(Get-Date -Format "MM/dd/yyyy HH:mm:ss.fff") Elevated privilege (run as Admininstrator) is required to run PSSDIAG. Exiting..." exit } } catch { Write-Error "Error occured in $($MyInvocation.MyCommand), $($PSItem.Exception.Message ), line number: $($PSItem.InvocationInfo.ScriptLineNumber)" exit } } function FindSQLDiag () { try { [bool]$is64bit = $false [xml]$xmlDocument = Get-Content -Path .\pssdiag.xml [string]$sqlver = $xmlDocument.dsConfig.Collection.Machines.Machine.Instances.Instance.ssver #first find out if their registry is messed up ValidateCurrentVersion -ssver $sqlver [string[]] $valid_versions = "10", "10.50", "11", "12", "13", "14", "15", "16" while ($sqlver -notin $valid_versions) { Write-Warning "An invalid version is specified for SQL Server (ssver = '$sqlver') in the pssdiag.xml file. This prevents selecting correct SQLDiag.exe path." $sqlver = Read-Host "Please enter the 2-digit version of your SQL Server ($valid_versions) to help locate SQLDiag.exe" } if ($sqlver -eq "10.50") { $sqlver = "10" } [string]$plat = $xmlDocument.dsConfig.DiagMgrInfo.IntendedPlatform [string] $x86Env = [Environment]::GetEnvironmentVariable( "CommonProgramFiles(x86)"); #[System.Environment]::Is64BitOperatingSystem if ($x86Env -ne $null) { $is64bit = $true } $toolsRegStr = ("HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\" + $sqlver+"0\Tools\ClientSetup") # for higher versions of PS use: [string]$toolsBinFolder = Get-ItemPropertyValue -Path $toolsRegStr -Name Path [string]$toolsBinFolder = (Get-ItemProperty -Path $toolsRegStr -Name Path).Path #strip "(x86)" in case Powershell goes to HKLM\SOFTWARE\WOW6432Node\Microsoft\Microsoft SQL Server\ under the covers, which it does $toolsBinFolderx64 = $toolsBinFolder.Replace("Program Files (x86)", "Program Files") $sqldiagPath = ($toolsBinFolder + "sqldiag.exe") $sqldiagPathx64 = ($toolsBinFolderx64 + "sqldiag.exe") if ((Test-Path -Path $sqldiagPathx64)) { return $sqldiagPathx64 } else { #path was not valid so checking second path if ($sqldiagPath -ne $sqldiagPathx64) { if ((Test-Path -Path $sqldiagPath)) { return $sqldiagPath } } Write-Host "$(Get-Date -Format "MM/dd/yyyy HH:mm:ss.fff") Unable to find 'sqldiag.exe' version: $($sqlver)0 on this machine. Data collection will fail" return "Path_Error_" } } catch { Write-Error "Error occured in finding SQLDiag.exe: $($PSItem.Exception.Message) line number: $($PSItem.InvocationInfo.ScriptLineNumber)" return "Path_Error_" } } function ValidateCurrentVersion ([string]$ssver) { [string[]] $intermediateNames = @() [string[]] $currentVersionReg = @() $regInstNames = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL" $instNames = Get-Item $regInstNames | Select-Object -ExpandProperty Property # add the discovered values in an array foreach ($inst in $instNames) { # for higher versions of Powershell use: $intermediateNames+= ( Get-ItemPropertyValue -Path $regInstNames -Name $inst) $intermediateNames+= ( Get-ItemProperty -Path $regInstNames -Name $inst).$inst } [int] $nonMatchCounter = 0 foreach($name in $intermediateNames) { $regRoot = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\" + $name + "\MSSQLServer\CurrentVersion" # for higher versions of PS use: $verString = Get-ItemPropertyValue -Path $regRoot -Name CurrentVersion $verString = (Get-ItemProperty -Path $regRoot -Name CurrentVersion).CurrentVersion $currentVersionReg+= ($regRoot + "=>" + $verString) # get the major version value from the reg entry $majVersion = $verString.Substring(0, $verString.IndexOf(".")) # for version 2008R2 number is 10.50 and we had to remove .50 #IndexOf function returns -1 for SQLs without minor version number (only 2008R2 has this number, which is 50. All others are zero). if ($ssver.IndexOf(".") -eq -1) { $tempssver = $ssver } else { $tempssver = $ssver.Substring(0, $ssver.IndexOf(".")) } if ($majVersion -ne $tempssver) { $nonMatchCounter++ } } if ($nonMatchCounter -eq $intermediateNames.Count) { Write-Warning "Collection may fail. No instance was found for the version of SQL Server configured in pssdiag.xml (ssver='$ssver')." Write-Warning "Examine these reg keys to see if the one or more versions is different from expected version $ssver (first 2 digits in NN.n.nnnn):`n" foreach ($entry in $currentVersionReg) { Write-Warning $entry } } } function PrintHelp { Write-Host " [-I cfgfile] = sets the configuration file, typically either pssdiag.xml or sqldiag.xml.`n"` "[-O outputpath] = sets the output folder. Defaults to startupfolder\SQLDIAG (if the folder does not exist, the collector will attempt to create it) `n" ` "[-N #] = output folder management at startup #: 1 = overwrite (default), 2 = rename (format is OUTPUT_00001,...00002, etc.) `n" ` "[-P supportpath] = sets the support path folder. Defaults to startupfolder if not specified `n" ` "[-M machine1 [machine2 machineN]|`@machinelistfile] = overrides the machines specified in the config file. When specifying more than one machine, separate each machine name with a space. "`@" specifies a machine list file `n" ` "[-Q] = quiet mode -- supresses prompts (e.g., password prompts) `n" ` "[-C #] = file compression type: 0 = none (default), 1 = NTFS, 2 = CAB `n" ` "[-G] = generic mode -- SQL Server connectivity checks are not enforced; machine enumeration includes all servers, not just SQL Servers `n" ` "[-R] = registers the collector as a service `n" ` "[-U] = unregisters the collector as a service `n" ` "[-A appname] = sets the application name. If running as a service, this sets the service name `n" ` "[-L] = continuous mode -- automatically restarts when shutdown via -X or -E `n" ` "[-X] = snapshot mode -- takes a snapshot of all configured diagnostics and shuts down immediately `n" ` "[-B [+]YYYYMMDD_HH:MM:SS] = specifies the date/time to begin collecting data; "+HH:MM:SS" specifies a relative time `n" ` "[-E [+]YYYYMMDD_HH:MM:SS] = specifies the date/time to end data collection; "+HH:MM:SS" specifies a relative time `n" ` "[-T {tcp[,port]|np|lpc|via}] = connects to sql server using the specified protocol `n" ` "[-Debug] = print some verbose messages for debugging where appropriate `n" ` "[START], [STOP], [STOP_ABORT] = service commands for a registered (-R) SQLDIAG service `n" ` "" -ForegroundColor Green exit } function main { [bool] $debug_on = $false if ($DebugOn -eq $true) { $debug_on = $true } if (Check-ElevatedAccess -eq $true) { exit } $validFileAttributes = Confirm-FileAttributes $debug_on if (-not($validFileAttributes)){ Write-Host "$(Get-Date -Format "MM/dd/yyyy HH:mm:ss.fff") File attribute validation FAILED. Exiting..." -ForegroundColor Red return } [string[]] $argument_array = @() if ($ServiceState -iin "stop", "start", "stop_abort") { Write-Host "ServiceState = $ServiceState" $argument_array += $ServiceState } elseif (($ServiceState -iin "--?", "/?", "?", "--help", "help") -or ($help -eq $true) ) { PrintHelp } else { # [/I cfgfile] = sets the configuration file, typically either sqldiag.ini or sqldiag.xml. Default is sqldiag.xml $lv_I = "/I" + $I # [/O outputpath] = sets the output folder. Defaults to startupfolder\SQLDIAG (if the folder does not exist, the collector will attempt to create it) #if this is a full directory path make sure to trim a final backslash because SQLDiag would fail to start the service if that exists if ($O.Substring($O.Length -1) -eq "`\") { $O = $O.Substring(0,$O.Length -1) } $lv_O = "/O" + $O # [/P supportpath] = sets the support path folder. By default, /P is set to the folder where the SQLdiag executable resides. # The support folder contains SQLdiag support files, such as the XML configuration file, Transact-SQL scripts, and other files that the utility uses during diagnostics collection. # If you use this option to specify an alternate support files path, SQLdiag will automatically copy the support files it requires to the specified folder if they do not already exist. $pwd = Get-Location if ([string]::IsNullOrWhiteSpace($P) -eq $false) { #trim a final backslash because SQLDiag would fail to start the service if that exists if ($P.Substring($P.Length -1) -eq "`\") { $P = $P.Substring(0,$P.Length -1) } $lv_P = "/P" + $P } else { $lv_P = "/P" + $pwd.Path } # [/N #] = output folder management at startup #: 1 = overwrite (default), 2 = rename (format is OUTPUT_00001,...00002, etc.) $lv_N = "/N" + $N # [/M machine1 [machine2 machineN]|@machinelistfile] = overrides the machines specified in the config file. When specifying more than one machine, separate each machine name with a space. "@" specifies a machine list file if ([string]::IsNullOrWhiteSpace($M)) { $lv_M = "" } else { $lv_M = "/M" + $M } # [/Q] = quiet mode -- supresses prompts (e.g., password prompts) if ($Q -eq $false) { $lv_Q = "" } else { $lv_Q = "/Q" } # [/C #] = file compression type: 0 = none (default), 1 = NTFS, 2 = CAB $lv_C = "/C" + $C # [/G] = generic mode -- SQL Server connectivity checks are not enforced; machine enumeration includes all servers, not just SQL Servers if ($G -eq $false) { $lv_G = "" } else { $lv_G = "/G" } # [/R] = registers the collector as a service if ($R -eq $false) { $lv_R = "" } else { $lv_R = "/R" } # [/U] = unregisters the collector as a service if ($U -eq $false) { $lv_U = "" } else { $lv_U = "/U" } # [/A appname] = sets the application name to DIAG$appname. If running as a service, this sets the service name to DIAG$appname if ([string]::IsNullOrWhiteSpace($A)) { $lv_A = "" } else { $lv_A = "/A" + $A } # [/L] = continuous mode -- automatically restarts when shutdown via /X or /E if ($L -eq $false) { $lv_L = "" } else { $lv_L = "/L" } # [/X] = snapshot mode -- takes a snapshot of all configured diagnostics and shuts down immediately if ($X -eq $false) { $lv_X = "" } else { $lv_X = "/X" } # [/B [+]YYYYMMDD_HH:MM:SS] = specifies the date/time to begin collecting data; "+" specifies a relative time if ([string]::IsNullOrWhiteSpace($B)) { $lv_B = "" } else { $lv_B = "/B" + $B } # [/E [+]YYYYMMDD_HH:MM:SS] = specifies the date/time to end data collection; "+" specifies a relative time if ([string]::IsNullOrWhiteSpace($E)) { $lv_E = "" } else { $lv_E = "/E" + $E } # [/T {tcp[,port]|np|lpc|via}] = connects to sql server using the specified protocol if ([string]::IsNullOrWhiteSpace($T)) { $lv_T = "" } else { $lv_T = "/T" + $T } [string[]] $argument_arrayTemp = @() if ($lv_U -eq "/U") { $argument_arrayTemp = $lv_A, $lv_U } else { # special case if user typed /r instead of -R if ($ServiceState -eq "/r") { $lv_R = "/R" } $argument_arrayTemp = $lv_I, $lv_O, $lv_P, $lv_N, $lv_M, $lv_Q, $lv_C, $lv_G, $lv_R, $lv_A, $lv_L, $lv_X, $lv_B, $lv_E, $lv_T } foreach ($item in $argument_arrayTemp) { if (($item.Trim()) -ne "") { $argument_array += $item.Trim() } } } # locate the SQLDiag.exe path for this version of PSSDIAG [string]$sqldiag_path = FindSQLDiag if ("Path_Error_" -eq $sqldiag_path) { #no valid path found to run SQLDiag.exe, so exiting exit } #Translate Performance Counters if((Get-WinSystemLocale).name -notlike "en*") & .\perfmon_translate.ps1 # launch the sqldiag.exe process and print the last 5 lines of the console file in case there were errors Write-Host "$(Get-Date -Format "MM/dd/yyyy HH:mm:ss.fff") Executing: $sqldiag_path $argument_array" Write-Host "$(Get-Date -Format "MM/dd/yyyy HH:mm:ss.fff") Number of parameters passed: $($argument_array.Length)" & $sqldiag_path $argument_array $console_log = ".\output\internal\##console.log" if (($R -eq $true) -or ($ServiceState -in "stop", "start", "stop_abort") -or ($U -eq $true)) { if($R -eq $true) { Write-Host "$(Get-Date -Format "MM/dd/yyyy HH:mm:ss.fff") Registered SQLDiag as a service. Please make sure you run 'pssdiag.ps1 START' or 'SQLDIAG START' or 'net start SQLDIAG'" -ForegroundColor Green } if($U -eq $true) { Write-Host "$(Get-Date -Format "MM/dd/yyyy HH:mm:ss.fff") Un-registered SQLDiag as a service." -ForegroundColor Green } } elseif (Test-Path -Path $console_log ) { Write-Warning "$(Get-Date -Format "MM/dd/yyyy HH:mm:ss.fff") Displaying the last 5 lines from \output\internal\##console.log file. If SQLDiag did not run for some reason, you may be reading an old log." Get-Content -Tail 5 $console_log Write-Host "$(Get-Date -Format "MM/dd/yyyy HH:mm:ss.fff") SQLDiag has completed. You can close the window. If you got errors, please review \output\internal\##SQLDIAG.LOG file" } } main
======================rtrim.vbs=================================
if (WScript.Arguments.Length <> 2) then WScript.Echo "Usage: rtrim.vbs infile outfile" WScript.Quit (-1) end if Set fso = CreateObject("Scripting.FileSystemObject") set File = fso.OpenTextFile (WScript.Arguments (0), 1, False) set OutFile = fso.OpenTextFile (WScript.Arguments(1), 2, True) While not File.AtEndOfStream OutFile.WriteLine (RTrim (File.ReadLine)) WEnd File.Close OutFile.Close
===============================run_in_dir.cmd===========================================
@echo off pushd cd /d %2 %1 >nul 2>&1 popd