From 8f97728208ee9662864fe8e1bd2b8aa909ebab7f Mon Sep 17 00:00:00 2001 From: ctrlbold Date: Wed, 14 Dec 2016 12:25:19 +0100 Subject: [PATCH 01/10] updated docs, cleaned up code a bit --- functions/Export-DbaAvailabiltyGroup.ps1 | 256 +++++++++++------------ 1 file changed, 127 insertions(+), 129 deletions(-) diff --git a/functions/Export-DbaAvailabiltyGroup.ps1 b/functions/Export-DbaAvailabiltyGroup.ps1 index b34df6cdbf..de2e5bb95c 100644 --- a/functions/Export-DbaAvailabiltyGroup.ps1 +++ b/functions/Export-DbaAvailabiltyGroup.ps1 @@ -2,12 +2,10 @@ { <# .SYNOPSIS -Export SQL Server Availability Groups to a T-SQL file. +Exports SQL Server Availability Groups to a T-SQL file. .DESCRIPTION -Export SQL Server Availability Groups creation scripts to a T-SQL file. This is a function that is not available in SSMS. - -THIS CODE IS PROVIDED "AS IS", WITH NO WARRANTIES. +Exports SQL Server Availability Groups creation scripts to a T-SQL file. This is a function that is not available in SSMS. .PARAMETER SqlServer The SQL Server instance name. SQL Server 2012 and above supported. @@ -37,151 +35,151 @@ Confirms each step/line of output .NOTES Author: Chris Sommer (@cjsommer), cjsommmer.com -dbatools PowerShell module (https://dbatools.io, clemaire@gmail.com) +dbatools PowerShell module (https://dbatools.io) Copyright (C) 2016 Chrissy LeMaire - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. .LINK https://dbatools.io/Export-DbaAvailabilityGroup .EXAMPLE -Export-DbaAvailabilityGroup -SqlServer sql2012 -FilePath 'C:\temp\availability_group_exports' - -Exports all Availability Groups from SQL server "sql2012". Output scripts are witten to the C:\temp\availability_group_exports directory. +Export-DbaAvailabilityGroup -SqlServer sql2012 +Exports all Availability Groups from SQL server "sql2012". Output scripts are written to the Documents\SqlAgExports directory by default. + .EXAMPLE -Export-DbaAvailabilityGroup -SqlServer sql2012 -FilePath 'C:\temp\availability_group_exports' -AvailabilityGroups AG1,AG2 +Export-DbaAvailabilityGroup -SqlServer sql2012 -FilePath C:\temp\availability_group_exports -Exports Availability Groups AG1 and AG2 from SQL server "sql2012". Output scripts are witten to the C:\temp\availability_group_exports directory. +Exports all Availability Groups from SQL server "sql2012". Output scripts are written to the C:\temp\availability_group_exports directory. .EXAMPLE -Export-DbaAvailabilityGroup -SqlServer sql2014 -FilePath 'C:\temp\availability_group_exports' -NoClobber +Export-DbaAvailabilityGroup -SqlServer sql2012 -FilePath 'C:\dir with spaces\availability_group_exports' -AvailabilityGroups AG1,AG2 -Exports all Availability Groups from SQL server "sql2014". Output scripts are witten to the C:\temp\availability_group_exports directory. If the export file already exists it will not be overwritten. +Exports Availability Groups AG1 and AG2 from SQL server "sql2012". Output scripts are written to the C:\dir with spaces\availability_group_exports directory. -.LINK -https://dbatools.io/Export-DbaAvailabilityGroup +.EXAMPLE +Export-DbaAvailabilityGroup -SqlServer sql2014 -FilePath C:\temp\availability_group_exports -NoClobber + +Exports all Availability Groups from SQL server "sql2014". Output scripts are written to the C:\temp\availability_group_exports directory. If the export file already exists it will not be overwritten. #> - [CmdletBinding(SupportsShouldProcess = $true)] + [CmdletBinding(SupportsShouldProcess = $true)] Param ( - [parameter(Mandatory = $true, ValueFromPipeline = $true)] - [Alias("ServerInstance", "SqlInstance")] - [object[]]$SqlServer, - + [parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Alias("ServerInstance", "SqlInstance")] + [object[]]$SqlServer, [System.Management.Automation.PSCredential]$SqlCredential, - [Alias("OutputLocation", "Path")] - [string]$FilePath, - - [switch]$NoClobber + [string]$FilePath = "$([Environment]::GetFolderPath("MyDocuments"))\SqlAgExport", + [switch]$NoClobber ) - + DynamicParam { if ($SqlServer) { return Get-ParamSqlAvailabilityGroups -SqlServer $SqlServer -SqlCredential $SqlCredential } } - BEGIN - { - Write-Output "Beginning Export-DbaAvailabilityGroup on '$SqlServer'" - $AvailabilityGroups = $PSBoundParameters.AvailabilityGroups - - Write-Verbose "Connecting to SqlServer '$SqlServer'" - - try { - $server = Connect-SqlServer -SqlServer $SqlServer -SqlCredential $SqlCredential - } catch { - if ($server.count -eq 1) { - throw $_ - } else { - Write-Warning "Can't connect to $SqlServer. Moving on." - Continue - } - } - } - - PROCESS - { - # Get all of the Availability Groups and filter if required - $AllAGs = $server.AvailabilityGroups - - if ($AvailabilityGroups) { - Write-Verbose 'Filtering AvailabilityGroups' - $AllAGs = $AllAGs | Where-Object {$_.name -in $AvailabilityGroups} - } - - if ($AllAGs.count -gt 0) { - - # Set and create the OutputLocation if it doesn't exist - $SQLINST = $SQLServer.Replace('\','$') - $OutputLocation = "${FilePath}\${SQLINST}" - - if (!(Test-Path $OutputLocation -PathType Container)) { - New-Item -Path $OutputLocation -ItemType Directory -Force | Out-Null - } - - # Script each Availability Group - foreach ($ag in $AllAGs) { - $AGName = $ag.Name - - # Set the outfile name - if ($AppendDateToOutputFilename.IsPresent) { - $Dttm = (Get-Date -Format 'yyyyMMdd_hhmm') - $OutFile = "${OutputLocation}\${AGname}_${Dttm}.sql" - } else { - $OutFile = "${OutputLocation}\${AGname}.sql" - } - - # Check NoClobber and script out the AG - if ($NoClobber.IsPresent -and (Test-Path -Path $OutFile -PathType Leaf)) { - Write-Warning "OutputFile '$OutFile' already exists. Skipping due to -NoClobber parameter" - } else { - Write-output "Scripting Availability Group [$AGName] on [$SQLServer] to '$OutFile'" - - # Create comment block header for AG script - "/*" | Out-File -FilePath $OutFile -Encoding ASCII -Force - " * Created by dbatools 'Export-DbaAvailabilityGroup' cmdlet on '$(Get-Date)'" | Out-File -FilePath $OutFile -Encoding ASCII -Append - " * See https://dbatools.io/Export-DbaAvailabilityGroup for more help" | Out-File -FilePath $OutFile -Encoding ASCII -Append - - # Output AG and listener names - " *" | Out-File -FilePath $OutFile -Encoding ASCII -Append - " * Availability Group Name: $($ag.name)" | Out-File -FilePath $OutFile -Encoding ASCII -Append - $ag.AvailabilityGroupListeners | % {" * Listener Name: $($_.name)"} | Out-File -FilePath $OutFile -Encoding ASCII -Append - - # Output all replicas - " *" | Out-File -FilePath $OutFile -Encoding ASCII -Append - $ag.AvailabilityReplicas | % {" * Replica: $($_.name)"} | Out-File -FilePath $OutFile -Encoding ASCII -Append - - # Output all databases - " *" | Out-File -FilePath $OutFile -Encoding ASCII -Append - $ag.AvailabilityDatabases | % {" * Database: $($_.name)"} | Out-File -FilePath $OutFile -Encoding ASCII -Append - - # $ag | Select-Object -Property * | Out-File -FilePath $OutFile -Encoding ASCII -Append - - "*/" | Out-File -FilePath $OutFile -Encoding ASCII -Append - - # Script the AG - $ag.Script() | Out-File -FilePath $OutFile -Encoding ASCII -Append - } - } - } else { - Write-Output "No Availability Groups detected on '$SqlServer'" - } - } - - END - { + BEGIN + { + Write-Output "Beginning Export-DbaAvailabilityGroup on $SqlServer" + $AvailabilityGroups = $PSBoundParameters.AvailabilityGroups + + Write-Verbose "Connecting to SqlServer $SqlServer" + + try + { + $server = Connect-SqlServer -SqlServer $SqlServer -SqlCredential $SqlCredential + } + catch + { + Write-Warning "Can't connect to $SqlServer. Moving on." + Continue + } + } + + PROCESS + { + # Get all of the Availability Groups and filter if required + $allags = $server.AvailabilityGroups + + if ($AvailabilityGroups) + { + Write-Verbose 'Filtering AvailabilityGroups' + $allags = $allags | Where-Object { $_.name -in $AvailabilityGroups } + } + + if ($allags.count -gt 0) + { + + # Set and create the OutputLocation if it doesn't exist + $sqlinst = $SQLServer.Replace('\', '$') + $OutputLocation = "$FilePath\$sqlinst" + + if (!(Test-Path $OutputLocation -PathType Container)) + { + New-Item -Path $OutputLocation -ItemType Directory -Force | Out-Null + } + + # Script each Availability Group + foreach ($ag in $allags) + { + $agname = $ag.Name + + # Set the outfile name + if ($AppendDateToOutputFilename.IsPresent) + { + $formatteddate = (Get-Date -Format 'yyyyMMdd_hhmm') + $outfile = "$OutputLocation\${AGname}_${formatteddate}.sql" + } + else + { + $outfile = "$OutputLocation\$agname.sql" + } + + # Check NoClobber and script out the AG + if ($NoClobber.IsPresent -and (Test-Path -Path $outfile -PathType Leaf)) + { + Write-Warning "OutputFile $outfile already exists. Skipping due to -NoClobber parameter" + } + else + { + Write-output "Scripting Availability Group [$agname] on $SQLServer to $outfile" + + # Create comment block header for AG script + "/*" | Out-File -FilePath $outfile -Encoding ASCII -Force + " * Created by dbatools 'Export-DbaAvailabilityGroup' cmdlet on '$(Get-Date)'" | Out-File -FilePath $outfile -Encoding ASCII -Append + " * See https://dbatools.io/Export-DbaAvailabilityGroup for more help" | Out-File -FilePath $outfile -Encoding ASCII -Append + + # Output AG and listener names + " *" | Out-File -FilePath $outfile -Encoding ASCII -Append + " * Availability Group Name: $($ag.name)" | Out-File -FilePath $outfile -Encoding ASCII -Append + $ag.AvailabilityGroupListeners | ForEach-Object { " * Listener Name: $($_.name)" } | Out-File -FilePath $outfile -Encoding ASCII -Append + + # Output all replicas + " *" | Out-File -FilePath $outfile -Encoding ASCII -Append + $ag.AvailabilityReplicas | ForEach-Object { " * Replica: $($_.name)" } | Out-File -FilePath $outfile -Encoding ASCII -Append + + # Output all databases + " *" | Out-File -FilePath $outfile -Encoding ASCII -Append + $ag.AvailabilityDatabases | ForEach-Object { " * Database: $($_.name)" } | Out-File -FilePath $outfile -Encoding ASCII -Append + + # $ag | Select-Object -Property * | Out-File -FilePath $outfile -Encoding ASCII -Append + + "*/" | Out-File -FilePath $outfile -Encoding ASCII -Append + + # Script the AG + $ag.Script() | Out-File -FilePath $outfile -Encoding ASCII -Append + } + } + } + else + { + Write-Output "No Availability Groups detected on $SqlServer" + } + } + + END + { $server.ConnectionContext.Disconnect() - If ($Pscmdlet.ShouldProcess("console", "Showing finished message")) { Write-Output "Completed Export-DbaAvailabilityGroup on '$SqlServer'" } - } + If ($Pscmdlet.ShouldProcess("console", "Showing finished message")) { Write-Output "Completed Export-DbaAvailabilityGroup on $SqlServer" } + } } \ No newline at end of file From d7b2c307232cd1fa8ce234cafa07132337fa99d5 Mon Sep 17 00:00:00 2001 From: ctrlbold Date: Wed, 14 Dec 2016 12:52:29 +0100 Subject: [PATCH 02/10] updated docs, fixed a multi server bug --- functions/Test-DbaValidLogin.ps1 | 473 ++++++++++++++++--------------- 1 file changed, 238 insertions(+), 235 deletions(-) diff --git a/functions/Test-DbaValidLogin.ps1 b/functions/Test-DbaValidLogin.ps1 index 114d8a5678..856d539bf0 100644 --- a/functions/Test-DbaValidLogin.ps1 +++ b/functions/Test-DbaValidLogin.ps1 @@ -2,7 +2,7 @@ { <# .SYNOPSIS -Test-DbaADLogin Finds any logins on SQL instance that are AD logins with either disabled AD user accounts or ones that nolonger exist +Test-DbaValidLogin Finds any logins on SQL instance that are AD logins with either disabled AD user accounts or ones that nolonger exist .DESCRIPTION The purpose of this function is to find SQL Server logins that are used by active directory users that are either disabled or removed from the domain. It allows you to @@ -46,17 +46,17 @@ https://dbatools.io/Test-DbaValidLogin .EXAMPLE Test-DbaValidLogin -SqlServer Dev01 -Returns all logins in the domain ran from (check $env:domain) that are either disabled or do not exist +Tests all logins in the domain ran from (check $env:domain) that are either disabled or do not exist .EXAMPLE Test-DbaValidLogin -SqlServer Dev01 -FilterBy GroupsOnly -Detailed -Returns all Active directory groups that have logins on Dev01 returning a detailed view. +Tests all Active directory groups that have logins on Dev01 returning a detailed view. .EXAMPLE -Test-DbaValidLogin -SqlServer Dev01 -ExcludeDomains "mydomain" +Test-DbaValidLogin -SqlServer Dev01 -ExcludeDomains subdomain.ad.local -Returns all logins excluding any that are from the mydomain Domain +Tests all logins excluding any that are from the mydomain Domain #> [CmdletBinding()] @@ -138,268 +138,271 @@ Returns all logins excluding any that are from the mydomain Domain PROCESS { - try + foreach ($instance in $sqlserver) { - $server = Connect-SqlServer -SqlServer $SqlServer -SqlCredential $sqlcredential - Write-Verbose "Connected to: $SqlServer" - } - catch - { - Write-Warning "Failed to connect to: $SqlServer" - continue - } - - if ($Logins) - { - $windowslogins = $server.Logins | Where-Object { $Logins -contains $_.Name } - } - else - { - switch ($FilterBy) + try { - - - "LoginsOnly" - { - Write-Verbose "connecting to logins" - $windowslogins = $server.Logins | Where-Object { $_.LoginType -eq 'WindowsUser' } - $windowslogins = $windowslogins | Where-Object { $_.Name.StartsWith("NT ") -eq $false -and $_.Name.StartsWith($SqlServer) -eq $false -and $_.Name.StartsWith("BUILTIN") -eq $false } - } - "GroupsOnly" - { - Write-Verbose "connecting to groups" - $windowsGroups = $server.Logins | Where-Object { $_.LoginType -eq 'WindowsGroup' } - $windowsGroups = $windowsGroups | Where-Object { $_.Name.StartsWith("NT ") -eq $false -and $_.Name -notmatch $SqlServer -and $_.Name.StartsWith("BUILTIN") -eq $false } - } - "None" - { - Write-Verbose "connecting to both logins and groups" - $allwindowsloginsgroups = $server.Logins | Where-Object { $_.LoginType -eq 'WindowsUser' -or $_.LoginType -eq 'WindowsGroup' } - $windowslogins = $allwindowsloginsgroups | Where-Object { $_.LoginType -eq 'WindowsUser' } - $windowslogins = $windowslogins | Where-Object { $_.Name.StartsWith("NT ") -eq $false -and $_.Name.StartsWith($SqlServer) -eq $false -and $_.Name.StartsWith("BUILTIN") -eq $false } - $windowsGroups = $allwindowsloginsgroups | Where-Object { $_.LoginType -eq 'WindowsGroup' } - $windowsGroups = $windowsGroups | Where-Object { $_.Name.StartsWith("NT ") -eq $false -and $_.Name -notmatch $SqlServer -and $_.Name.StartsWith("BUILTIN") -eq $false } - } - + $server = Connect-SqlServer -SqlServer $instance -SqlCredential $sqlcredential + Write-Verbose "Connected to: $instance" } - } - - if ($exclude) - { - $windowslogins = $windowslogins | Where-Object { $Logins -notcontains $_.Name } - $windowsGroups = $windowsGroups | Where-Object { $Logins -notcontains $_.Name } - - } - - foreach ($login in $windowslogins) - { - - $adlogin = $login.Name - Write-Verbose "Parsing Login $adlogin" - $domain, $username = $adlogin.Split("\") - $filter = "(&(objectCategory=User)(sAMAccountName=$username))" # won't work with groups - Write-Verbose $filter - - if ($env:USERDOMAIN -eq $domain) + catch { - $searcher = New-Object System.DirectoryServices.DirectorySearcher - $searcher.Filter = $filter + Write-Warning "Failed to connect to: $instance" + continue } - else + + if ($Logins) { - $LDAP = ($domains | Where-Object NetBios -eq $domain).LDAP - $ad = New-Object System.DirectoryServices.DirectoryEntry $LDAP - $searcher = New-Object System.DirectoryServices.DirectorySearcher - $searcher.SearchRoot = $ad - $searcher.Filter = $filter + $windowslogins = $server.Logins | Where-Object { $Logins -contains $_.Name } } - try + else { - $founduser = $searcher.findOne() + switch ($FilterBy) + { + + + "LoginsOnly" + { + Write-Verbose "connecting to logins" + $windowslogins = $server.Logins | Where-Object { $_.LoginType -eq 'WindowsUser' } + $windowslogins = $windowslogins | Where-Object { $_.Name.StartsWith("NT ") -eq $false -and $_.Name.StartsWith($SqlServer) -eq $false -and $_.Name.StartsWith("BUILTIN") -eq $false } + } + "GroupsOnly" + { + Write-Verbose "connecting to groups" + $windowsGroups = $server.Logins | Where-Object { $_.LoginType -eq 'WindowsGroup' } + $windowsGroups = $windowsGroups | Where-Object { $_.Name.StartsWith("NT ") -eq $false -and $_.Name -notmatch $SqlServer -and $_.Name.StartsWith("BUILTIN") -eq $false } + } + "None" + { + Write-Verbose "connecting to both logins and groups" + $allwindowsloginsgroups = $server.Logins | Where-Object { $_.LoginType -eq 'WindowsUser' -or $_.LoginType -eq 'WindowsGroup' } + $windowslogins = $allwindowsloginsgroups | Where-Object { $_.LoginType -eq 'WindowsUser' } + $windowslogins = $windowslogins | Where-Object { $_.Name.StartsWith("NT ") -eq $false -and $_.Name.StartsWith($SqlServer) -eq $false -and $_.Name.StartsWith("BUILTIN") -eq $false } + $windowsGroups = $allwindowsloginsgroups | Where-Object { $_.LoginType -eq 'WindowsGroup' } + $windowsGroups = $windowsGroups | Where-Object { $_.Name.StartsWith("NT ") -eq $false -and $_.Name -notmatch $SqlServer -and $_.Name.StartsWith("BUILTIN") -eq $false } + } + + } } - catch + + if ($exclude) { - Write-Warning "AD Searcher Error for $username" + $windowslogins = $windowslogins | Where-Object { $Logins -notcontains $_.Name } + $windowsGroups = $windowsGroups | Where-Object { $Logins -notcontains $_.Name } + } - $value = $founduser.Properties.useraccountcontrol - - $enabled = $exists = $false - $adlogindetails = 'unknown' - ## values from http://www.netvision.com/ad_useraccountcontrol.php - switch ($value) + foreach ($login in $windowslogins) { - 512 { - $enabled = $true - $adlogindetails = 'Enabled Account' - } - 514 { - $enabled = $false - $adlogindetails = 'Disabled Account' - } - 544 { - $enabled = $true - $adlogindetails = 'Enabled, Password Not Required' - } - 546 { - $enabled = $false - $adlogindetails = 'Disabled, Password Not Required' - } - 66048 { - $enabled = $true - $adlogindetails = 'Enabled, Password Doesnt Expire' - } - 66050 { - $enabled = $false - $adlogindetails = 'Disabled, Password Doesnt Expire' + + $adlogin = $login.Name + Write-Verbose "Parsing Login $adlogin" + $domain, $username = $adlogin.Split("\") + $filter = "(&(objectCategory=User)(sAMAccountName=$username))" # won't work with groups + Write-Verbose $filter + + if ($env:USERDOMAIN -eq $domain) + { + $searcher = New-Object System.DirectoryServices.DirectorySearcher + $searcher.Filter = $filter } - 66080 { - $enabled = $true - $adlogindetails = 'Enabled, Password Doesnt Expire & Not Required' + else + { + $LDAP = ($domains | Where-Object NetBios -eq $domain).LDAP + $ad = New-Object System.DirectoryServices.DirectoryEntry $LDAP + $searcher = New-Object System.DirectoryServices.DirectorySearcher + $searcher.SearchRoot = $ad + $searcher.Filter = $filter } - 66082 { - $enabled = $false - $adlogindetails = 'Disabled, Password Doesnt Expire & Not Required' + try + { + $founduser = $searcher.findOne() } - 262656 { - $enabled = $true - $adlogindetails = 'Enabled, Smartcard Required' + catch + { + Write-Warning "AD Searcher Error for $username" } - 262658 { - $enabled = $false - $adlogindetails = 'Disabled, Smartcard Required' + $value = $founduser.Properties.useraccountcontrol + + $enabled = $exists = $false + $adlogindetails = 'unknown' + + ## values from http://www.netvision.com/ad_useraccountcontrol.php + switch ($value) + { + 512 { + $enabled = $true + $adlogindetails = 'Enabled Account' + } + 514 { + $enabled = $false + $adlogindetails = 'Disabled Account' + } + 544 { + $enabled = $true + $adlogindetails = 'Enabled, Password Not Required' + } + 546 { + $enabled = $false + $adlogindetails = 'Disabled, Password Not Required' + } + 66048 { + $enabled = $true + $adlogindetails = 'Enabled, Password Doesnt Expire' + } + 66050 { + $enabled = $false + $adlogindetails = 'Disabled, Password Doesnt Expire' + } + 66080 { + $enabled = $true + $adlogindetails = 'Enabled, Password Doesnt Expire & Not Required' + } + 66082 { + $enabled = $false + $adlogindetails = 'Disabled, Password Doesnt Expire & Not Required' + } + 262656 { + $enabled = $true + $adlogindetails = 'Enabled, Smartcard Required' + } + 262658 { + $enabled = $false + $adlogindetails = 'Disabled, Smartcard Required' + } + 262688 { + $enabled = $true + $adlogindetails = 'Enabled, Smartcard Required, Password Not Required' + } + 262690 { + $enabled = $false + $adlogindetails = 'Disabled, Smartcard Required, Password Not Required' + } + 328192 { + $enabled = $true + $adlogindetails = 'Enabled, Smartcard Required, Password Doesnt Expire' + } + 328194 { + $enabled = $false + $adlogindetails = 'Disabled, Smartcard Required, Password Doesnt Expire' + } + 328224 { + $enabled = $true + $adlogindetails = 'Enabled, Smartcard Required, Password Doesnt Expire & Not Required' + } + 328226 { + $enabled = $false + $adlogindetails = 'Disabled, Smartcard Required, Password Doesnt Expire & Not Required' + } + 590336 + { + $enabled = $true + $adlogindetails = 'Enabled, User Cannot Change Password & Password Never Expires' + } + $null + { + $exists = $true + } + default + { + Write-Verbose "unknown value passed from useraccountcontrol Server: $sqlServer Login: $username Domain: $domain Value: $value" + $exists = 'Unknown' + $enabled = 'Unknown' + } } - 262688 { - $enabled = $true - $adlogindetails = 'Enabled, Smartcard Required, Password Not Required' + + if ($Detailed) + { + [PSCustomObject]@{ + Server = $server.Name + Domain = $domain + Login = $username + Type = "User" + Found = $exists -ne $true + Enabled = $enabled + DisabledInSQLServer = $login.IsDisabled + ADLoginDetails = $adlogindetails + } } - 262690 { - $enabled = $false - $adlogindetails = 'Disabled, Smartcard Required, Password Not Required' + else + { + [PSCustomObject]@{ + Server = $server.Name + Domain = $domain + Login = $username + Type = "User" + Found = $exists -ne $true + Enabled = $enabled + } } - 328192 { - $enabled = $true - $adlogindetails = 'Enabled, Smartcard Required, Password Doesnt Expire' + } # foreach login + + foreach ($login in $windowsGroups) + { + $adlogin = $login.Name + Write-Verbose "Parsing Group $adlogin" + $domain, $username = $adlogin.Split("\") + $filter = "(&(objectCategory=group)(sAMAccountName=$username))" # won't work with groups + Write-Verbose $filter + + if ($env:USERDOMAIN -eq $domain) + { + $searcher = New-Object System.DirectoryServices.DirectorySearcher + $searcher.Filter = $filter } - 328194 { - $enabled = $false - $adlogindetails = 'Disabled, Smartcard Required, Password Doesnt Expire' + else + { + $LDAP = ($domains | Where-Object NetBios -eq $domain).LDAP + $ad = New-Object System.DirectoryServices.DirectoryEntry $LDAP + $searcher = New-Object System.DirectoryServices.DirectorySearcher($ad) + $searcher.SearchRoot = $ad + $searcher.Filter = $filter } - 328224 { - $enabled = $true - $adlogindetails = 'Enabled, Smartcard Required, Password Doesnt Expire & Not Required' + try + { + $founduser = $searcher.findOne() } - 328226 { - $enabled = $false - $adlogindetails = 'Disabled, Smartcard Required, Password Doesnt Expire & Not Required' + catch + { + Write-Warning "AD Searcher Error for $username on $SqlServer" } - 590336 + + $enabled = $exists = $false + + if ($founduser) { $enabled = $true - $adlogindetails = 'Enabled, User Cannot Change Password & Password Never Expires' } - $null + else { $exists = $true } - default + if ($Detailed) { - Write-Verbose "unknown value passed from useraccountcontrol Server: $sqlServer Login: $username Domain: $domain Value: $value" - $exists = 'Unknown' - $enabled = 'Unknown' - } - } - - if ($Detailed) - { - [PSCustomObject]@{ - Server = $server.Name - Domain = $domain - Login = $username - Type = "User" - Found = $exists -ne $true - Enabled = $enabled - DisabledInSQLServer = $login.IsDisabled - ADLoginDetails = $adlogindetails - } - } - else - { - [PSCustomObject]@{ - Server = $server.Name - Domain = $domain - Login = $username - Type = "User" - Found = $exists -ne $true - Enabled = $enabled - } - } - } # foreach login - - foreach ($login in $windowsGroups) - { - $adlogin = $login.Name - Write-Verbose "Parsing Group $adlogin" - $domain, $username = $adlogin.Split("\") - $filter = "(&(objectCategory=group)(sAMAccountName=$username))" # won't work with groups - Write-Verbose $filter - - if ($env:USERDOMAIN -eq $domain) - { - $searcher = New-Object System.DirectoryServices.DirectorySearcher - $searcher.Filter = $filter - } - else - { - $LDAP = ($domains | Where-Object NetBios -eq $domain).LDAP - $ad = New-Object System.DirectoryServices.DirectoryEntry $LDAP - $searcher = New-Object System.DirectoryServices.DirectorySearcher($ad) - $searcher.SearchRoot = $ad - $searcher.Filter = $filter - } - try - { - $founduser = $searcher.findOne() - } - catch - { - Write-Warning "AD Searcher Error for $username on $SqlServer" - } - - $enabled = $exists = $false - - if ($founduser) - { - $enabled = $true - } - else - { - $exists = $true - } - if ($Detailed) - { - [PSCustomObject]@{ - Server = $server.Name - Domain = $domain - Login = $username - Type = "Group" - Found = $exists -ne $true - Enabled = $enabled - DisabledInSQLServer = $login.IsDisabled - ADLoginDetails = 'AD group' + [PSCustomObject]@{ + Server = $server.Name + Domain = $domain + Login = $username + Type = "Group" + Found = $exists -ne $true + Enabled = $enabled + DisabledInSQLServer = $login.IsDisabled + ADLoginDetails = 'AD group' + } } - } - else - { - [PSCustomObject]@{ - Server = $server.Name - Domain = $domain - Login = $username - Type = "Group" - Found = $exists -ne $true - Enabled = $enabled + else + { + [PSCustomObject]@{ + Server = $server.Name + Domain = $domain + Login = $username + Type = "Group" + Found = $exists -ne $true + Enabled = $enabled + } } - } - } # foreach group + } # foreach group + } } } \ No newline at end of file From 3a6e3f8166f3c442d8bb8ba60a1cf05b6bcb4c9b Mon Sep 17 00:00:00 2001 From: ctrlbold Date: Wed, 14 Dec 2016 13:18:53 +0100 Subject: [PATCH 03/10] removed extra space --- functions/Test-DbaValidLogin.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/functions/Test-DbaValidLogin.ps1 b/functions/Test-DbaValidLogin.ps1 index 856d539bf0..9cbb95e50d 100644 --- a/functions/Test-DbaValidLogin.ps1 +++ b/functions/Test-DbaValidLogin.ps1 @@ -159,8 +159,6 @@ Tests all logins excluding any that are from the mydomain Domain { switch ($FilterBy) { - - "LoginsOnly" { Write-Verbose "connecting to logins" From b2e8e9eca5e21d2d1ff779cee8d48e0808f5a38a Mon Sep 17 00:00:00 2001 From: ctrlbold Date: Wed, 14 Dec 2016 14:11:33 +0100 Subject: [PATCH 04/10] fixed some words, added some words --- functions/Get-DbaDatabaseSnapshot.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/functions/Get-DbaDatabaseSnapshot.ps1 b/functions/Get-DbaDatabaseSnapshot.ps1 index cadf949c50..a953bc79c0 100644 --- a/functions/Get-DbaDatabaseSnapshot.ps1 +++ b/functions/Get-DbaDatabaseSnapshot.ps1 @@ -34,17 +34,17 @@ You should have received a copy of the GNU General Public License along with thi .EXAMPLE Get-DbaDatabaseSnapshot -SqlServer sqlserver2014a -Returns a custom object displaying Server, Database, DatabaseCreated, SnapshotOf +Returns a custom object displaying Server, Database, DatabaseCreated, SnapshotOf, SizeMB, DatabaseCreated, IsReadCommittedSnapshotOn, SnapshotIsolationState .EXAMPLE Get-DbaDatabaseSnapshot -SqlServer sqlserver2014a -Databases HR, Accounting -Returns informations for database snapshots having HR and Accounting as base dbs +Returns information for database snapshots having HR and Accounting as base dbs .EXAMPLE Get-DbaDatabaseSnapshot -SqlServer sqlserver2014a -Snapshots HR_snapshot, Accounting_snapshot -Returns informations for database snapshots HR_snapshot and Accounting_snapshot +Returns information for database snapshots HR_snapshot and Accounting_snapshot #> [CmdletBinding()] From cfbd22e544edd3737a240bda53668a9d3d1a6ebf Mon Sep 17 00:00:00 2001 From: ctrlbold Date: Wed, 14 Dec 2016 14:23:41 +0100 Subject: [PATCH 05/10] added support for multiple servers, made output more accurate --- functions/Resolve-DbaNetworkName.ps1 | 147 +++++++++++++++------------ 1 file changed, 83 insertions(+), 64 deletions(-) diff --git a/functions/Resolve-DbaNetworkName.ps1 b/functions/Resolve-DbaNetworkName.ps1 index a572e5b21c..bdb766df74 100644 --- a/functions/Resolve-DbaNetworkName.ps1 +++ b/functions/Resolve-DbaNetworkName.ps1 @@ -35,77 +35,96 @@ You should have received a copy of the GNU General Public License along with thi .EXAMPLE Resolve-DbaNetworkName -ComputerName ServerA +Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain + +.EXAMPLE +Resolve-DbaNetworkName -SqlServer sql2016\sqlexpress + +Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain + +.EXAMPLE +Resolve-DbaNetworkName -SqlServer sql2016\sqlexpress, sql2014 + Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain +Get-SqlRegisteredServerName -SqlServer sql2014 | Resolve-DbaNetworkName + +Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain #> [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] - [Alias("cn", "host", "ServerInstance", "SqlInstance","Server","SqlServer")] + [parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Alias("cn", "host", "ServerInstance", "SqlInstance", "Server", "SqlServer")] [object]$ComputerName, [PsCredential]$Credential ) - - $conn = $ipaddress = $CIMsession = $null - if ($ComputerName.GetType() -eq [Microsoft.SqlServer.Management.Smo.Server]) - { - $ComputerName = $ComputerName.NetName - } - - $ComputerName = $ComputerName.Split('\')[0] - Write-Verbose "Connecting to server $ComputerName" - $ipaddress = ((Test-Connection -ComputerName $ComputerName -Count 1 -ErrorAction SilentlyContinue).Ipv4Address).IPAddressToString - - if ( $ipaddress ) - { - if ( $host.Version.Major -gt 2 ) - { - Write-Verbose "Your PowerShell Version is $($host.Version.Major)" - Write-Verbose "IP Address from $computername is $ipaddress" - try - { - Write-Verbose "Getting computer information from server $ComputerName via CIM (WinRM)" - $CIMsession = New-CimSession -ComputerName $ComputerName -ErrorAction SilentlyContinue -Credential $Credential - $conn = Get-CimInstance -Query "Select Name, Caption, DNSHostName, Domain FROM Win32_computersystem" -CimSession $CIMsession - } - catch - { - Write-Warning "No WinRM connection to $computername" - } - if (!$conn) - { - try - { - Write-Verbose "Getting computer information from server $ComputerName via CIM (DCOM)" - $sessionoption = New-CimSessionOption -Protocol DCOM - $CIMsession = New-CimSession -ComputerName $ComputerName -SessionOption $sessionoption -ErrorAction SilentlyContinue -Credential $Credential - $conn = Get-CimInstance -Query "Select Name, Caption, DNSHostName, Domain FROM Win32_computersystem" -CimSession $CIMsession - } - catch - { - Write-Warning "No DCOM connection to $computername" - } - } - } - if (!$conn) - { - Write-Verbose "Getting computer information from server $ComputerName via WMI (DCOM)" - $conn = Get-WmiObject -ComputerName $ComputerName -Query "Select Name, Caption, DNSHostName, Domain FROM Win32_computersystem" -ErrorAction SilentlyContinue -Credential $Credential - } - - [PSCustomObject]@{ - InputName = $computername - ComputerName = $conn.Name - IPAddress = $ipaddress - DNSHostName = $conn.DNSHostname - Domain = $conn.Domain - } - } - - else - { - Write-Warning "Computer $computername not available" - } - + PROCESS + { + foreach ($Computer in $ComputerName) + { + $conn = $ipaddress = $CIMsession = $null + + if ($Computer.GetType() -eq [Microsoft.SqlServer.Management.Smo.Server]) + { + $Computer = $Computer.NetName + } + + $OGComputer = $Computer + $Computer = $Computer.Split('\')[0] + Write-Verbose "Connecting to server $Computer" + $ipaddress = ((Test-Connection -ComputerName $Computer -Count 1 -ErrorAction SilentlyContinue).Ipv4Address).IPAddressToString + + if ($ipaddress) + { + if ($host.Version.Major -gt 2) + { + Write-Verbose "Your PowerShell Version is $($host.Version.Major)" + Write-Verbose "IP Address from $Computer is $ipaddress" + try + { + Write-Verbose "Getting computer information from server $Computer via CIM (WinRM)" + $CIMsession = New-CimSession -ComputerName $Computer -ErrorAction SilentlyContinue -Credential $Credential + $conn = Get-CimInstance -Query "Select Name, Caption, DNSHostName, Domain FROM Win32_computersystem" -CimSession $CIMsession + } + catch + { + Write-Verbose "No WinRM connection to $Computer" + } + if (!$conn) + { + try + { + Write-Verbose "Getting computer information from server $Computer via CIM (DCOM)" + $sessionoption = New-CimSessionOption -Protocol DCOM + $CIMsession = New-CimSession -ComputerName $Computer -SessionOption $sessionoption -ErrorAction SilentlyContinue -Credential $Credential + $conn = Get-CimInstance -Query "Select Name, Caption, DNSHostName, Domain FROM Win32_computersystem" -CimSession $CIMsession + } + catch + { + Write-Warning "No DCOM connection to $Computer" + } + } + } + if (!$conn) + { + Write-Verbose "Getting computer information from server $Computer via WMI (DCOM)" + $conn = Get-WmiObject -ComputerName $Computer -Query "Select Name, Caption, DNSHostName, Domain FROM Win32_computersystem" -ErrorAction SilentlyContinue -Credential $Credential + } + + [PSCustomObject]@{ + InputName = $OGComputer + ComputerName = $conn.Name + IPAddress = $ipaddress + DNSHostName = $conn.DNSHostname + Domain = $conn.Domain + } + } + + else + { + Write-Warning "Computer $Computer not available" + } + } + } } \ No newline at end of file From 5568beec530372955002e249c3901a3ff660b67c Mon Sep 17 00:00:00 2001 From: ctrlbold Date: Wed, 14 Dec 2016 14:26:01 +0100 Subject: [PATCH 06/10] added fqdn --- functions/Resolve-DbaNetworkName.ps1 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/functions/Resolve-DbaNetworkName.ps1 b/functions/Resolve-DbaNetworkName.ps1 index bdb766df74..1875e9a155 100644 --- a/functions/Resolve-DbaNetworkName.ps1 +++ b/functions/Resolve-DbaNetworkName.ps1 @@ -2,7 +2,7 @@ { <# .SYNOPSIS -Returns information about the network connection of the target computer including NetBIOS name, IP Address and domain name. +Returns information about the network connection of the target computer including NetBIOS name, IP Address, domain name and fully qualified domain name (FQDN). .DESCRIPTION Retrieves the IPAddress, ComputerName from one computer. @@ -35,21 +35,21 @@ You should have received a copy of the GNU General Public License along with thi .EXAMPLE Resolve-DbaNetworkName -ComputerName ServerA -Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain +Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain, FQDN .EXAMPLE Resolve-DbaNetworkName -SqlServer sql2016\sqlexpress -Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain +Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain, FQDN .EXAMPLE Resolve-DbaNetworkName -SqlServer sql2016\sqlexpress, sql2014 -Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain +Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain, FQDN Get-SqlRegisteredServerName -SqlServer sql2014 | Resolve-DbaNetworkName -Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain +Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain, FQDN #> [CmdletBinding()] param ( @@ -118,6 +118,7 @@ Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostNa IPAddress = $ipaddress DNSHostName = $conn.DNSHostname Domain = $conn.Domain + FQDN = "$($conn.DNSHostname).$($conn.Domain)" } } From 00d7b203754559fb0608d08e8f444c0526a5e1dd Mon Sep 17 00:00:00 2001 From: ctrlbold Date: Wed, 14 Dec 2016 14:30:33 +0100 Subject: [PATCH 07/10] updated docs --- functions/Resolve-DbaNetworkName.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/functions/Resolve-DbaNetworkName.ps1 b/functions/Resolve-DbaNetworkName.ps1 index 1875e9a155..60e2236b1f 100644 --- a/functions/Resolve-DbaNetworkName.ps1 +++ b/functions/Resolve-DbaNetworkName.ps1 @@ -35,21 +35,21 @@ You should have received a copy of the GNU General Public License along with thi .EXAMPLE Resolve-DbaNetworkName -ComputerName ServerA -Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain, FQDN +Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain, FQDN for ServerA .EXAMPLE Resolve-DbaNetworkName -SqlServer sql2016\sqlexpress -Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain, FQDN +Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain, FQDN for the SQL instance sql2016\sqlexpress .EXAMPLE Resolve-DbaNetworkName -SqlServer sql2016\sqlexpress, sql2014 -Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain, FQDN +Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain, FQDN for the SQL instance sql2016\sqlexpress and sql2014 Get-SqlRegisteredServerName -SqlServer sql2014 | Resolve-DbaNetworkName -Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain, FQDN +Returns a custom object displaying InputName, ComputerName, IPAddress, DNSHostName, Domain, FQDN for all SQL Servers returned by Get-SqlRegisteredServerName #> [CmdletBinding()] param ( From 4d0a46e72dde4800e27d56e0155c8f463345eecf Mon Sep 17 00:00:00 2001 From: ctrlbold Date: Wed, 14 Dec 2016 16:24:23 +0100 Subject: [PATCH 08/10] cleaned up --- functions/Test-DbaMaxMemory.ps1 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/functions/Test-DbaMaxMemory.ps1 b/functions/Test-DbaMaxMemory.ps1 index f201e0f942..ef24c8e8c0 100644 --- a/functions/Test-DbaMaxMemory.ps1 +++ b/functions/Test-DbaMaxMemory.ps1 @@ -10,8 +10,6 @@ total memory, currently configured SQL max memory, and the calculated recommenda Jonathan notes that the formula used provides a *general recommendation* that doesn't account for everything that may be going on in your specific environment. -THIS CODE IS PROVIDED "AS IS", WITH NO WARRANTIES. - .PARAMETER SqlServer Allows you to specify a comma separated list of servers to query. @@ -23,9 +21,6 @@ $cred = Get-Credential, then pass $cred variable to this parameter. Windows Authentication will be used when SqlCredential is not specified. To connect as a different Windows user, run PowerShell as that user. .NOTES -Author : Chrissy LeMaire (@cl), netnerds.net -Requires: sysadmin access on SQL Servers - dbatools PowerShell module (https://dbatools.io, clemaire@gmail.com) Copyright (C) 2016 Chrissy LeMaire From ea20e1dde7fd46b3e54dfef794037af2ddc8078d Mon Sep 17 00:00:00 2001 From: ctrlbold Date: Wed, 14 Dec 2016 17:24:52 +0100 Subject: [PATCH 09/10] cleanup docs --- functions/Get-DbaMaxMemory.ps1 | 11 ++--------- functions/Set-DbaMaxMemory.ps1 | 5 ----- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/functions/Get-DbaMaxMemory.ps1 b/functions/Get-DbaMaxMemory.ps1 index 7e94c5f181..db03b6dcfa 100644 --- a/functions/Get-DbaMaxMemory.ps1 +++ b/functions/Get-DbaMaxMemory.ps1 @@ -2,14 +2,10 @@ Function Get-DbaMaxMemory { <# .SYNOPSIS -Gets the 'Max Server Memory' configuration setting and the memory of the server. -Works on SQL Server 2000-2014. +Gets the 'Max Server Memory' configuration setting and the memory of the server. Works on SQL Server 2000-2014. .DESCRIPTION -This cmdlet retrieves the SQL Server 'Max Server Memory' configuration setting as well as the total -physical installed on the server. - -THIS CODE IS PROVIDED "AS IS", WITH NO WARRANTIES. +This command retrieves the SQL Server 'Max Server Memory' configuration setting as well as the total physical installed on the server. .PARAMETER SqlServer Allows you to specify a comma separated list of servers to query. @@ -22,9 +18,6 @@ $cred = Get-Credential, then pass $cred variable to this parameter. Windows Authentication will be used when SqlCredential is not specified. To connect as a different Windows user, run PowerShell as that user. .NOTES -Author : Chrissy LeMaire (@cl), netnerds.net -Requires: sysadmin access on SQL Servers - dbatools PowerShell module (https://dbatools.io, clemaire@gmail.com) Copyright (C) 2016 Chrissy LeMaire diff --git a/functions/Set-DbaMaxMemory.ps1 b/functions/Set-DbaMaxMemory.ps1 index 42536b7ba6..f5b9825f01 100644 --- a/functions/Set-DbaMaxMemory.ps1 +++ b/functions/Set-DbaMaxMemory.ps1 @@ -3,7 +3,6 @@ Function Set-DbaMaxMemory <# .SYNOPSIS Sets SQL Server 'Max Server Memory' configuration setting to a new value then displays information this setting. -Works on SQL Server 2000-2014. .DESCRIPTION Sets SQL Server max memory then displays information relating to SQL Server Max Memory configuration settings. @@ -14,7 +13,6 @@ determine the default optimum RAM to use, then sets the SQL max value to that nu Jonathan notes that the formula used provides a *general recommendation* that doesn't account for everything that may be going on in your specific environment. -THIS CODE IS PROVIDED "AS IS", WITH NO WARRANTIES. .PARAMETER SqlServer Allows you to specify a comma separated list of servers to query. @@ -34,9 +32,6 @@ Windows Authentication will be used if SqlCredential is not specified. SQL Serve Results of Get-DbaMaxMemory to be passed into the command .NOTES -Author : Chrissy LeMaire (@cl), netnerds.net -Requires: sysadmin access on SQL Servers - dbatools PowerShell module (https://dbatools.io, clemaire@gmail.com) Copyright (C) 2016 Chrissy LeMaire From cb61266f9c23a4f108e6c090791bf39ce5b79a7e Mon Sep 17 00:00:00 2001 From: ctrlbold Date: Wed, 14 Dec 2016 17:26:11 +0100 Subject: [PATCH 10/10] upped version --- dbatools.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbatools.psd1 b/dbatools.psd1 index c34470114c..d5e696ca4b 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -11,7 +11,7 @@ RootModule = 'dbatools.psm1' # Version number of this module. - ModuleVersion = '0.8.69' + ModuleVersion = '0.8.691' # ID used to uniquely identify this module GUID = '9d139310-ce45-41ce-8e8b-d76335aa1789'