diff --git a/Intro_Powershell_SQL_DBA.pdf b/Intro_Powershell_SQL_DBA.pdf index aedd3ec..c664e48 100644 Binary files a/Intro_Powershell_SQL_DBA.pdf and b/Intro_Powershell_SQL_DBA.pdf differ diff --git a/Old/1-Powershell_Basics.ps1 b/Old/1-Powershell_Basics.ps1 deleted file mode 100644 index 57ed72d..0000000 --- a/Old/1-Powershell_Basics.ps1 +++ /dev/null @@ -1,318 +0,0 @@ -#A few things before we get started(these need to be run as administrator) -Update-Help -Set-ExecutionPolicy RemoteSigned - -#Execution policies are a security feature to protect against malicious scripts -get-help about_executionpolicies - -#What version are we using? -$PSVersionTable - -#Cmdlets - the core functionality -Get-Command -Get-Command | Measure-Object #Don't worry about the pipe yet, we'll cover that later - -Get-Command -Name *New* - -#Verb-Noun construction -#Makes things very intuitive -#Limited number of verbs for standardization -Get-Verb - -#Unlimited number of nouns - -#Cmdlets can have aliases to make them easier to use -dir C:\ - -#dir is and alias for Get-ChildItem -Get-ChildItem C:\ - -#We can see all the aliases for a cmdlet -Get-Alias -Definition Get-ChildItem - -#let's use a cmdlet to make a new directory -New-Item -ItemType Directory 'C:\TEMP' - -#Providers - Drives and more -Get-PSDrive - -#Note the different types of providers -dir ENV:\ - -dir ALIAS:\ - -#You can reference these values from the command line -$env:computername -$env:username -$Alias:ls - -#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -#The three most important cmdlets you need to remember -#The Holy Trinity of Self Discovery -#Get-Command -#Get-Help -#Get-Member -#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -Get-Help Get-Command -Get-Help Get-Command -Full -Get-Help Get-Command -ShowWindow -Get-Help about_Providers -ShowWindow -man Get-Command -Full -help Get-Command -Full - -#Get-Member is important for Powershell variables - -#Variables and using variables -Get-Help about_variables - -#Powershell variables start with a $ -$string="This is a variable" -$string - -#We can use Get-Member to find out all the information on our objects -$string | Get-Member - -#Powershell is strongly typed and uses .Net objects. -#Not just limited to strings and intgers - -$date=Get-Date -$date -$date | gm #gm is the alias of Get-Member - -#Because they are .Net types/classes, we can use the methods and properties. -$date.Day -$date.DayOfWeek -$date.DayOfYear -$date.ToUniversalTime() - -#Powershell tries to figure out the variable type when it can(implicit types) -#We can also explicitly declare our type -[string]$datestring = Get-Date #could also use [System.String] -$datestring -$datestring|gm - -#Variable Typing can get you in to trouble, so be careful. - -#EVERYTHING is an object. This means more than just basic types: -$file = New-Item -ItemType File -Path 'C:\TEMP\junkfile.txt' -$file | gm - -$file.Name -$file.FullName -$file.Extension -$file.LastWriteTime - -#note that the values for properties are objects to, and the Get-Member will show you what those objects are. -#This means we can apply those properties and methods to the return values. -$file.Directory | gm -$file.Directory.EnumerateFiles() - -#let's clean up that file using the method -$file.Delete() - -#note, the object is still in memory, but doesn't really exist -#You can check that using the object's methods, though -$file -dir C:\TEMP -$file.Refresh() -$file -$file.Exists - -#cmdlets and functions will output objects. You can work with them by using () -(Get-ChildItem C:\Windows).Length - -(Get-Date).AddDays(-3) - -#Concatenation and Interpolation -#The plus sign is used for concatenation - -$temperature = 'Hot' -'Tea. Earl Grey. ' + $temperature + '.' - -#We can use interpolation to make life easier and cleaner. -#Interpolation is a useful tool when working with variables, especially strings. -"Tea. Earl Grey. $temperature." -'Tea. Earl Grey. $temperature.' - -#It is important to understand the difference between single and double quotes. - -#` (the tick on the tilde key) is the escape character, use this when you need to get around special characters -"Tea. Earl Grey. `$temperature." - -#The pipeline allows us to extend the functionality. -Get-Help about_pipelines -#It works something like a "gate" where everything thing on the left side that matches -#gets passed to the right. - -#we've used it already for Get-Member -(Get-ChildItem C:\) | Get-Member - -#We can also use it for performing an action on a object -dir \\PICARD\C$\backups\dummy\*.trn -dir \\PICARD\C$\backups\dummy\*.trn | Remove-Item -WhatIf - -#We can use the pipeline to further enhance our actions -dir \\PICARD\C$\backups\ -Recurse | Where-Object {$_.Extension -eq ".trn" -and $_.LastWriteTime -lt (Get-Date).AddDays(-1)} | rm -WhatIf - -#$_ means the current object in the pipeline. In the above example, we want to reference the Extension and LastWriteTime properties for the current object - - -#Operators and variable comparison -Get-Help about_operators - -#Symbols like '>' and '<' mean different things in standard shell scripting. - -#You use -lt, -ne, -eq, and other phrases are used to perform logical compariso -'1 -eq 2 returns:' + (1 -eq 2) -'1 -lt 2 returns:' + (1 -lt 2) - -#For multiple conditions, use -and and -or -'1 -eq 1 -or 1 -gt 2 returns:' + (1 -eq 1 -or 1 -gt 2) -'1 -eq 1 -and 1 -lt 2 returns:' + (1 -eq 1 -and 1 -lt 2) - -#Powershell also has control flow structures that you can use -#if(){ -#} - -#while/until(){ -#} -#do{ -#}while/until() - -#foreach(){ -#} - -#switch(){ -#} - -Get-Help about_If -Get-Help about_While -Get-Help about_ForEach -Get-Help about_Switch - -#Use If to check for things, like if a file or directory exists (and what to do if it doesn't) -New-Item -ItemType Directory -Path 'C:\TEMP' -If((Test-Path 'C:\TEMP') -eq $false){New-Item -ItemType Directory -Path 'C:\TEMP'} - -Remove-Item -Recurse 'C:\TEMP' -If((Test-Path 'C:\TEMP') -eq $false){New-Item -ItemType Directory -Path 'C:\TEMP'} - - -#while or until do things based on their conditions -#do is sytnax that allows you to put the while/until at the end of the loop instead of the beginning -$x=0 -while($x -lt 10){ - New-Item -ItemType File -Path "C:\TEMP\WhileJunk$x.txt" - $x++ -} - -dir C:\TEMP - -$x=0 -do{ - Remove-Item -Path "C:\TEMP\WhileJunk$x.txt" - $x++ -}until($x -ge 10 ) - -dir C:\TEMP - -#Collections and Arrays -Get-Help about_arrays - -#Arrays are useful ways to collect data -$list = @('PICARD','RIKER','WESLEY') -$list - -#Specify the specific item in an array with [] (0 based numbering) -"This is list item #2:"+ $list[1] - -#Use foreach to iterate through collections -foreach ($item in $list){ - "Item $item" | out-host -} - -#So now we can make a collection of other objects and process it using our control checks -$dirs = dir C:\ | Where-Object {$_.PSIsContainer -eq $true} -foreach($dir in $dirs){ - $fullname = $dir.FullName - $count = (dir $fullname | Measure-Object).Count - "$fullname - $count" - if($count -gt 10){ - "$fullname has lots of files!"| out-host - } - else{ - "$fullname is kind of puny."| out-host - } -} - -#Powershell supports error handling with standard syntax: try/catch/finally/throw -get-help about_try_catch_finally -get-help about_throw - - -try{ #the inital thing we try to do - "This is a code block" | Out-Host - throw (Write-warning "Then an Error happens....") -} -catch{ #What happens with an error - Write-Error "An error has occurred!" #using Write-Error actually feeds things to the host's error handling system -} -finally{ #optional, always happens - Write-host "Run a cleanup action" -ForegroundColor Green #Write-Host is generally not used, but here in this case to change text color -} - -#Powershell can interface with .Net libraries, COM objects, other functionality. -#For example, we can use Powershell to interact directly with the WMI -$wmi=Get-WmiObject -Class Win32_ComputerSystem -$wmi | Get-Member - -$wmi.NumberOfProcessors -$Wmi.NumberOfLogicalProcessors -$wmi.Domain - -#We can format output in a couple different ways. Table and list are the most commonly used options -$wmi | Format-List -$wmi | Format-Table -AutoSize - -#Note that the object doesn't display everything available. We can control this with Select-Object. -$wmi | Select-Object Name,Domain,TotalPhysicalMemory,NumberOfProcessors,Model | Format-List - -$wmi | Select-Object Name,Domain,TotalPhysicalMemory,NumberOfProcessors,Model | Format-Table -AutoSize - -#of course, we can get really fancy -#This funcion allows us to query all the attached volumes (disks and mountpoints) for size and freespace. -gwmi win32_volume -computername 'localhost' | where {$_.drivetype -eq 3} | Sort-Object name ` - | Format-Table name,@{l="Size(GB)";e={($_.capacity/1gb).ToString("F2")}},@{l="Free Space(GB)";e={($_.freespace/1gb).ToString("F2")}},@{l="% Free";e={(($_.Freespace/$_.Capacity)*100).ToString("F2")}} - -#Note the -computername parameter. We can execute the WMI call against a remote machine if we want. -#Working with our previous example, we could make a quick inventory report of our environment -$comps = Get-ADComputer -Filter 'ObjectClass -eq "Computer"' -Get-WmiObject -Class Win32_ComputerSystem -ComputerName $comps.name | Select-Object Name,Domain,TotalPhysicalMemory,NumberOfProcessors,Model | Format-Table -AutoSize - -#Many commands in Powershell can be used remotely. -Get-Help about_remote - -#We can also use an ssh-like command to enter a Powershell terminal session on a remote machine -Enter-PSSession -ComputerName PICARD - -$env:computername -$env:username -exit - -#Also, we can use the Invoke-Command cmdlet to run any command remotely. -[ScriptBlock]$cmd = {Test-Path -Path 'C:\DBFiles'} - -Invoke-Command -ComputerName PICARD -ScriptBlock $cmd - -#For these to work, Windows Remote Managment(WinRM) needs to be enabled and firewall rules set to allow the remote connections. - -#While we have a base set of cmdlets and functions, we can also extend Powershell through the use of modules and snap-ins -#Snap-ins were introduced in v1, but were replaced by modules in v2+ - -Import-Module ActiveDirectory -Get-Command -Module ActiveDirectory - -#With Powershell 3, modules can be implicitly loaded when you use a cmdlet from that module -Remove-Module ActiveDirectory -Get-ADDomain \ No newline at end of file diff --git a/Old/2-Powershell_Basics_Examples.ps1 b/Old/2-Powershell_Basics_Examples.ps1 deleted file mode 100644 index 468c1f6..0000000 --- a/Old/2-Powershell_Basics_Examples.ps1 +++ /dev/null @@ -1,98 +0,0 @@ -#basic Powershell use - -#already looked at deleting specific old files -dir C:\DBFiles\backups\backups\ -Recurse | Where-Object {$_.Extension -eq ".trn" -and $_.LastWriteTime -lt (Get-Date).AddDays(-3)} | rm -WhatIf - -#------------------------------------------------------------- -#We can use Get-Service to find our SQL Server services -Get-Service -computername PICARD *SQL* - -#What if we want to do a check for any SQL Server services not running? -Get-Service -computername PICARD *SQL* | Where-Object {$_.Status -ne 'Running' -and $_.Name -like 'MSSQL*'} - -#stop the service so it will cause an alert -Invoke-Command -ComputerName PICARD -scriptblock {Stop-Service MSSQLSERVER -force} - -#So it doesn't take much more to write a script to alert us if SQL Server isn't running -$svcs =Get-Service -computername PICARD *SQL* | Where-Object {$_.Status -ne 'Running' -and $_.Name -like 'MSSQL*'} - -$count = ($svcs | Measure-Object).Count -if($count -gt 0){ - Write-Warning "Count of stopped SQL Server instances is: $count" -} - -#We could get even more clever and start all the services from that object -foreach($svc in $svcs){ - Invoke-Command -ComputerName PICARD -scriptblock {Start-Service $svc} -} - - -#------------------------------------------------------------- -#Using Powershell to collect perfmon info - -$counters=@("\LogicalDisk(C:)\Disk Bytes/sec" -,"\LogicalDisk(C:)\Avg. Disk sec/read" -,"\LogicalDisk(C:)\Avg. Disk Sec/Write" -,"\LogicalDisk(C:)\Disk Transfers/sec") - -$sample = Get-Counter -Counter $counters -$sample.CounterSamples | Select-Object -Property Path,CookedValue,Timestamp | Format-Table -AutoSize - -#By creating a server list, we can execute our collection against multiple machines -$srvrs = @('HIKARUDC','PICARD') -$samples=@() - -foreach($srvr in $srvrs){ - $output=(Get-Counter -ComputerName $srvr -Counter $counters -ErrorAction SilentlyContinue).CounterSamples | Select-Object -Property Path,CookedValue,Timestamp - if($output -ne $null){ - $output | Add-Member -Type NoteProperty -Name Server -Value $srvr - $output | Add-Member -Type NoteProperty -Name fullmount -Value $cleanmp - $samples+=$output - } -} - -$samples | Select-Object -Property Path,CookedValue,Timestamp - -#------------------------------------------------------------- -#This was a simple script I used to mass convert RedGate Backup files to native. -$files = ls X:\Backups *_RG* - -foreach($x in $files){ - $old = $x.DirectoryName +"\" + $x.Name - $new = $x.DirectoryName +"\" + $x.Name.Replace("_RG","") - .\SQBConverter.exe $old $new - } - -#------------------------------------------------------------- -#You can use loops to selectively move files from one server to another -#this script moves all of Server A's transaction log backups to server B -$source = 'ServerA' -$target = 'ServerB' -$dirs = ls \\$source\backups | where {$_.Name -ne $source} -foreach($dir in $dirs){ - if(!(Test-Path -Path \\$target\backups\$dir\transactionlogs)){New-Item -ItemType Directory -Path \\$target\backups\$dir\transactionlogs} - robocopy \\$source\backups\$dir\transactionlogs \\$target\backups\$dir\transactionlogs -} - - -#------------------------------------------------------------- -#We can use some simple commands to build out restore statements for transaction logs -$path = 'C:\DBFiles\backups\backups' -$files = ls $path\*.trn | Sort-Object -Property lastwritetime -$out = @() -foreach($file in $files){ - $out += "RESTORE LOG [Vault_Xero] FROM DISK='W:\MSSQL\Backups\Vault_Xero\TransactionLogs\" + $file.name + "' WITH NORECOVERY" -} - -$out | Out-File -FilePath C:\TEMP\restorelogs.sql - - -#If you have a cluster, you can use the commands to create directories (or other work) on each node consistently -Import-Module FailoverClusters -$cname = (Get-Cluster -name 'ServerA').name -$nodes = (get-clusternode -Cluster $cname).name -$jobscript = 'C:\Users\Adm-mike.fal\Documents\Backup - Full - DBA Database.sql' -foreach($node in $nodes){ - "Connecting to $node" - sqlcmd -S $node -d msdb -i $jobscript -v RedeployJobs="YES" -} \ No newline at end of file diff --git a/Old/3-Working_With_SQL_Server.ps1 b/Old/3-Working_With_SQL_Server.ps1 deleted file mode 100644 index 97eef88..0000000 --- a/Old/3-Working_With_SQL_Server.ps1 +++ /dev/null @@ -1,256 +0,0 @@ -#Using SQL CMD -#sqlcmd - Just call within the script -sqlcmd -S PICARD -d tempdb -Q "select count(1) from sys.objects" - -#create a script, run it against multiple instances -$sql=" -SET NOCOUNT ON -select sp.name,count(1) db_count -from sys.server_principals sp -join sys.databases d on (sp.sid = d.owner_sid) -group by sp.name -" -sqlcmd -S PICARD -d tempdb -Q $sql - -#Multi-instance execution -cls -$instances = @("PICARD","PICARD\WESLEY") -foreach($instance in $instances){ - "Instance: $instance" - $out=sqlcmd -S $instance -Q $sql - $out |Format-Table -AutoSize -} - -#What kind of output is this? -$out[0].GetType().Name - -#Load the SQL Server Powershell module -Import-Module sqlps -verbose #-DisableNameChecking - -#What's available to us? -Get-Command -Module sqlps -Get-Command -Module sqlps | Measure-Object |Select Count - -#And we can use Get-Help to get more info -Get-Help Invoke-Sqlcmd -ShowWindow - -cls -foreach($instance in $instances){ - "Instance: $instance" - $ISout=Invoke-Sqlcmd -ServerInstance $instance -Query $sql - $ISout |ft -AutoSize -} - -$ISout | Get-Member - -#We can use Invoke-Sqlcmd almost like sqlcmd, but since we have a data row we can use it to easily drive other functionality -$instance = 'PICARD' -$dbs = Invoke-SqlCmd -ServerInstance $instance -Query "select name from sys.databases where database_id in (1,3,4)" -foreach ($db in $dbs.name){ - $dbname = $db.TrimEnd() - $sql = "BACKUP DATABASE $dbname TO DISK='C:\DBFiles\Backups\$instance-$dbname.bak' WITH COMPRESSION,INIT" - Invoke-SqlCmd -ServerInstance $instance -Query $sql -} - -cd c:\ -dir '\\PICARD\C$\DBFiles\backups' - -#SQL Provider -#-------------------------------------- -#By loading SQLPS,we also load the SQL Server Provider -cls -Get-PSDrive - -#Change to the SQL Server Provider -CD SQLSERVER:\ -dir - -#We can browse our SQL Servers as if they were directories -cls -CD SQL\PICARD\ -dir - -CD DEFAULT -dir - -dir Databases -dir databases -Force -$dbout = dir databases -Force -$dbout | gm -$dbout | where {$_.readonly -eq $false} - -$dbout | select name,createdate,@{name='DataSizeMB';expression={$_.dataspaceusage/1024}} | Format-Table -AutoSize - -#let's work with logins -$dblogins = dir logins -$dblogins -$dblogins | gm - -dir logins -Force| Select-Object name,defaultdatabase - - -#set all default dbs for non-system logins to tempdb -foreach($dblogin in $dblogins){ - if($dblogin.issystemobject -eq $false){ - $dblogin.defaultdatabase = 'tempdb' - } -} - -dir logins -Force| Select-Object name,defaultdatabase - -#Some of the generic functions won't work -New-Item database\poshtest - -#So we will need to use traditional methods -Invoke-Sqlcmd -ServerInstance PICARD -Database tempdb -Query "CREATE DATABASE poshtest" -dir databases - -#But other things do work -Remove-Item databases\poshtest -dir databases - -#Let's look at the CMS -CD "SQLSERVER:\SQLRegistration\Central Management Server Group\PICARD" -dir - -#we can see all the servers in our CMS -#now let's use it to run all our systemdb backups -cd C:\ -$servers= @((dir "SQLSERVER:\SQLRegistration\Central Management Server Group\PICARD").Name) -$servers += 'PICARD' - -foreach($server in $servers){ - - $dbs = Invoke-SqlCmd -ServerInstance $server -Query "select name from sys.databases where database_id in (1,3,4)" - $pathname= "C:\DBFiles\Backups\"+$server.Replace('\','_') - [scriptblock]$cmd = [scriptblock]::Create("if(!(test-path $pathname)){mkdir $pathname}") - Invoke-Command -ComputerName 'PICARD' -ScriptBlock $cmd - foreach ($db in $dbs.name){ - $dbname = $db.TrimEnd() - $sql = "BACKUP DATABASE $dbname TO DISK='$pathname\$dbname.bak' WITH COMPRESSION,INIT" - Invoke-SqlCmd -ServerInstance $server -Query $sql - } -} - -dir '\\PICARD\C$\DBFiles\Backups' -recurse - -#SMO -#Powershell can acess the .NET SMO libraries -[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null - -$smoserver = new-object ('Microsoft.SqlServer.Management.Smo.Server') 'PICARD' - -#We can now interact with the server as it is an object -$smoserver | Get-Member -$smoserver.Version - -#We can also drilldown into the parts of the server -$smoserver.Databases - -#now we have a table object with its own properties -$sysjobs = $smoserver.Databases["msdb"].Tables["sysjobs"] -$sysjobs | Get-Member -$sysjobs.Indexes -$sysjobs.Script() - -#we can now make collections -rm C:\IntroToPowershell\logins.sql -$logins= $smoserver.Logins -foreach($login in $logins) {$login.Script() >> C:\IntrotoPowershell\logins.sql} - -notepad C:\IntrotoPowershell\logins.sql - -#we can also create objects -#this is a little trickier - -$db = New-Object ('Microsoft.SqlServer.Management.Smo.Database') ($smoserver,'SMOTest') -$db | Get-Member - -#Just creating the new object doesn't mean it's created (look in SMO) -#so let's create it -$db.Create() - -#but we don't want the files in the default location. So now the fun begins. -$db.Drop() - -#First we have to declare our files -$dbname = 'SMOTest' -$db = New-Object ('Microsoft.SqlServer.Management.Smo.Database') ($smoserver,$dbname) -$fg = New-Object ('Microsoft.SqlServer.Management.Smo.FileGroup') ($db,'PRIMARY') -$mdf = New-Object ('Microsoft.SqlServer.Management.Smo.DataFile') ($fg,"$dbname`_data01") -$ldf = New-Object ('Microsoft.SqlServer.Management.Smo.LogFile') ($db,"$dbname`_log") -$mdf.FileName = "C:\DBFiles\Data\$dbname`_data01.mdf" -$mdf.Size = (100 * 1024) -$mdf.Growth = (10 * 1024) -$mdf.GrowthType = 'KB' -$db.FileGroups.Add($fg) -$fg.Files.Add($mdf) - -$ldf.FileName = "C:\DBFiles\Log\$dbname`_log.ldf" -$ldf.Size = (10 * 1024) -$ldf.Growth = (10 * 1024) -$ldf.GrowthType = 'KB' -$db.LogFiles.Add($ldf) - -#and we can look at the script to create it -$db.Script() - -#or we can just create it -$db.Create() - - -#Cleanup! -$db.Drop() - -#Agent Jobs -#SQL 2008 supports Powershell as a job step - -#Script 1 (backup user dbs, cleanup old files) - -#backup your databases -#get a collection of databases -$dbs = Invoke-Sqlcmd -ServerInstance localhost -Database tempdb -Query "SELECT name FROM sys.databases WHERE database_id > 4 and STATE_DESC = 'ONLINE'" - -#Get a formatted string for the datetime -$datestring = (Get-Date -Format 'yyyyMMddHHmm') - -#loop through the databases -foreach($db in $dbs.name){ - $dir = "C:\Backups\$db" - #does the backup directory exist? If not, create it - if(!(Test-Path $dir)){New-Item -ItemType Directory -path $dir} - - #Get a nice name and backup your database to it - $filename = "$db-$datestring.bak" - $backup=Join-Path -Path $dir -ChildPath $filename - $sql = "BACKUP DATABASE $db TO DISK = N'$backup' WITH COMPRESSION" - Invoke-Sqlcmd -ServerInstance localhost -Database tempdb -Query $sql -QueryTimeout 6000 - #Delete old backups - Get-ChildItem $dir\*.bak| Where {$_.LastWriteTime -lt (Get-Date).AddMinutes(-1)}|Remove-Item - -} - - -#script 2 - Backup user db logs -#backup your databases -#get a collection of databases -$dbs = Invoke-Sqlcmd -ServerInstance localhost -Database tempdb -Query "SELECT name FROM sys.databases WHERE database_id > 4 and STATE_DESC = 'ONLINE' and RECOVERY_MODEL_DESC != 'SIMPLE'" - -#Get a formatted string for the datetime -$datestring = (Get-Date -Format 'yyyyMMddHHmm') - -#loop through the databases -foreach($db in $dbs.name){ - $dir = "C:\Backups\$db" - #does the backup directory exist? If not, create it - if(!(Test-Path $dir)){New-Item -ItemType Directory -path $dir} - - #Get a nice name and backup your database to it - $filename = "$db-$datestring.trn" - $backup=Join-Path -Path $dir -ChildPath $filename - $sql = "BACKUP LOG $db TO DISK = N'$backup'" - Invoke-Sqlcmd -ServerInstance localhost -Database tempdb -Query $sql -QueryTimeout 6000 - #Delete old backups - Get-ChildItem $dir\*.trn| Where {$_.LastWriteTime -lt (Get-Date).AddDays(-3)}|Remove-Item - -} diff --git a/Old/4a-Working_with_SQL_examples.ps1 b/Old/4a-Working_with_SQL_examples.ps1 deleted file mode 100644 index 8023448..0000000 --- a/Old/4a-Working_with_SQL_examples.ps1 +++ /dev/null @@ -1,92 +0,0 @@ - -#Simple t-log restore script -if(Test-Path 'C:\IntroToPowershell\RestoreDummyLogs.sql'){Remove-Item 'C:\IntroToPowershell\RestoreDummyLogs.sql'} -$files = Get-ChildItem '\\picard\Backups\dummy\*.trn' | Sort-Object LastWriteTime -$files |ForEach-Object {"RESTORE DATABASE [dummy] FROM DISK=N`'" + $_.FullName + "`' WITH NORECOVERY" | Out-File -Append 'C:\IntroToPowershell\RestoreDummyLogs.sql' } - -#extract all your database schemas as dacpacs -$server = 'PICARD' -$dbs = Invoke-Sqlcmd -ServerInstance $server -Database tempdb -Query 'SELECT name FROM sys.databases WHERE database_id >4' - -foreach($db in $dbs.name){ - $cmd = "& 'C:\Program Files (x86)\Microsoft SQL Server\120\DAC\bin\sqlpackage.exe' /action:Extract /targetfile:'C:\IntroToPowershell\$db.dacpac' /SourceServerName:$server /SourceDatabaseName:$db" - Invoke-Expression $cmd -} - -#Add a list of servers to your CMS -$servers = @('RIKER','WORF') - -foreach ($server in $servers) -{ - - if (!(Test-Path $(Encode-Sqlname $server))) - { - New-Item $(Encode-Sqlname $server) ` - -itemtype registration ` - -Value “server=$server;integrated security=true;name=$server” - } -} - -#backup databases in parallel -$dbs = Invoke-Sqlcmd -ServerInstance PICARD -Database tempdb -Query "SELECT name FROM sys.databases WHERE database_id > 4" -$datestring = (Get-Date -Format 'yyyyMMddHHmm') - -foreach($db in $dbs.name){ - $dir = "C:\Backups\$db" - if(!(Test-Path $dir)){New-Item -ItemType Directory -path $dir} - - $filename = "$db-$datestring.bak" - $backup=Join-Path -Path $dir -ChildPath $filename - $sql = "BACKUP DATABASE $db TO DISK = N'$backup'" - $cmd = "Invoke-Sqlcmd -ServerInstance localhost -Database tempdb -Query `"$sql`" -QueryTimeout 6000;" - $cmd += "Get-ChildItem $dir\*.bak| Where {`$_.LastWriteTime -lt (Get-Date).AddMinutes(-1)}|Remove-Item;" - [scriptblock]$cmdblock = [ScriptBlock]::Create($cmd) - Start-Job $cmdblock -} - - -#change all service accounts for a list of servers -cd C:\ -$account = 'SDF\sqlsvc' -$password = 'SQLp@55word' -#$password = '73gnat!9' - -$servers= @('PICARD') - -foreach($server in $servers){ - $wmi = new-object ("Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer") $Server - $svcs = $wmi.services | where {$_.Type -eq 'SqlServer'} - - $svcs | Select-Object DisplayName,ServiceAccount - - foreach($svc in $svcs){ - try{ - $svc.SetServiceAccount($account,$password) - } - catch{ - write-error $error[0] - } - } - $svcs | Select-Object DisplayName,ServiceAccount -} - - -#Configure SQL Server with the SMO: -$smosrv = New-Object ('Microsoft.SqlServer.Management.Smo.Database') 'PICARD' - -$smosrv.Configuration.MaxServerMemory.ConfigValue = 1024 -$smosrv.Configuration.DefaultBackupCompression.ConfigValue = 1 -$smosrv.Configuration.IsSqlClrEnabled.ConfigValue = 1 -$smosrv.Configuration.OptimizeAdhocWorkLoads.ConfigValue = 1 -$smosrv.Configuration.Alter() - -$smosrv.AuditLevel = [Microsoft.SqlServer.Management.Smo.AuditLevel]::Failure -$smosrv.NumberOfLogFiles =99 -$smosrv.Alter() - -$smosrv.jobserver.MaximumHistoryRows = 100000 -$smosrv.jobserver.MaximumJobHistoryRows = 2000 -$smosrv.JobServer.Alter() - -$smosrv.databases['model'].RecoveryModel = 'Simple' -$smosrv.databases['model'].Alter() \ No newline at end of file diff --git a/Old/5-CodeReuse.ps1 b/Old/5-CodeReuse.ps1 deleted file mode 100644 index b0c58d4..0000000 --- a/Old/5-CodeReuse.ps1 +++ /dev/null @@ -1,124 +0,0 @@ -#Code reuse and extension -#Reusing scripts -#open 5a-FileCount.ps1 - -#now call the script -C:\IntroToPowershell\5a-FileCount.ps1 'C:\IntroToPowershell\' -C:\IntroToPowershell\5a-FileCount.ps1 'notvalid' - -#We can convert the script to a function call for better reuse -#open 5b-FileCount_Function.ps1 -C:\IntroToPowershell\5b-FileCount_Function.ps1 'C:\IntroToPowershell\' - -#funcations can be extremely useful for code reuse. For example, if we re-wrote our code for getting a free space report: - -function Get-FreeSpace{ - param([string] $hostname = ($env:COMPUTERNAME)) - - gwmi win32_volume -computername $hostname | where {$_.drivetype -eq 3} | Sort-Object name ` - | ft name,label,@{l="Size(GB)";e={($_.capacity/1gb).ToString("F2")}},@{l="Free Space(GB)";e={($_.freespace/1gb).ToString("F2")}},@{l="% Free";e={(($_.Freespace/$_.Capacity)*100).ToString("F2")}} - -} - -Get-FreeSpace PICARD -Get-FreeSpace localhost - -#They can get pretty advanced -#load assemblies -[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null -$ErrorActionPreference = 'Inquire' - -function Expand-SqlLogFile{ - param( - [string]$InstanceName = 'localhost', - [parameter(Mandatory=$true)][string] $DatabaseName, - [parameter(Mandatory=$true)][int] $LogSizeMB) - #Convert MB to KB (SMO works in KB) - [int]$LogFileSize = $LogSizeMB*1024 - - #Set base information - $srv = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server $InstanceName - $logfile = $srv.Databases[$DatabaseName].LogFiles[0] - $CurrSize = $logfile.Size - - #grow file - while($CurrSize -lt $LogFileSize){ - if(($LogFileSize - $CurrSize) -lt 8192000){$CurrSize = $LogFileSize} - else{$CurrSize += 8192000} - - $logfile.size = $CurrSize - $logfile.Alter() - } -} - -#But once you write it, it's easy to call -Expand-SqlLogFile -DatabaseName corruptme -LogSizeMB 12000 - -#We can put functions in the profile, giving us a re-usable toolkit -#working with the profile -#easiest way to edit is... -notepad $profile - -#The profile may not exist, so you'd have to create it -#Let's rename the profile so we can create it, then we'll clean up afterwards. -$profilebak = "$profile.bak" -Move-Item $profile $profilebak - -if(!(Test-Path $profile)){New-Item -Path $profile -ItemType file -Force} - -#see, created. Boom. Now I'm going to move the previous profile back. -Remove-Item $profile -Move-Item $profilebak $profile - -#We can use any of the functions in the profile, they're loaded at session start -Get-FreeSpace - -#Add log growth function -notepad $profile - -#If we make changes, we can reload by "executing" the profile -. $profile - -#now we can use the added function -Expand-SqlLogFile -InstanceName PICARD -DatabaseName corruptme -LogSizeMB 12000 - -#Working with modules -#We can get a listing of all our available modules -Get-Module -ListAvailable - -#SQLPS is provided with SQL2012 client tools -#It provides the SQLPS provider as well as some functions -Get-Command -Module SQLPS - -#What gets used a lot is Invoke-SqlCmd, a wrapper for sqlcmd - -#We can also write our own modules to extend Powershell -#let's take our file count function, open 5c-FileCount_module.psm1 -#once we import it, we can re-use it -Import-Module C:\IntroToPowershell\5c-FileCount_module.psm1 - -Get-FileCount 'C:\IntroToPowershell\' - -#Open up the SQLCheck module and examine the Test-SQLConnection function -#Now let's load the module -Import-Module SQLCheck - -#Now that function is available to us as if -Test-SQLConnection -Instances @('PICARD','PICARD\WESLEY','NotAValidServer') - -#Cool. Now let's have some fun - -$out = @() -for($port=1430;$port -le 1450;$port++){ - $row = Test-SQLConnection -Instances "PICARD,$port" | select InstanceName,StartupTime,@{name='Host';expression={'PICARD'}},@{name='Port';expression={"$port"}} - $out+=$row -} - -$out | Where-Object {$_.StartupTime -ne $null} | Format-Table - - -$CMS='PICARD' -$servers=@((dir "SQLSERVER:\SQLRegistration\Central Management Server Group\$CMS").Name) - -$servers+=$cms -Test-SQLConnection -Instances $servers \ No newline at end of file diff --git a/Old/5a-FileCount.ps1 b/Old/5a-FileCount.ps1 deleted file mode 100644 index 117a9fa..0000000 --- a/Old/5a-FileCount.ps1 +++ /dev/null @@ -1,9 +0,0 @@ -param([string]$PathName) - -if(Test-Path -Path $PathName){ - $FileCount = (Get-ChildItem $PathName).Length - "$PathName has $FileCount files" | Out-Host -} -else{ - Write-Warning "Path is invalid" -} diff --git a/Old/5b-FileCount_Function.ps1 b/Old/5b-FileCount_Function.ps1 deleted file mode 100644 index be7925a..0000000 --- a/Old/5b-FileCount_Function.ps1 +++ /dev/null @@ -1,16 +0,0 @@ -param($arg) - -function Get-FileCount{ - - param([string]$PathName) - - if(Test-Path -Path $PathName){ - $FileCount = (Get-ChildItem $PathName).Length - "$PathName has $FileCount files" | Out-Host - } - else{ - Write-Warning "Path is invalid" - } -} - -Get-FileCount -PathName $arg diff --git a/Old/5c-FileCount_module.psm1 b/Old/5c-FileCount_module.psm1 deleted file mode 100644 index bcbbbb8..0000000 --- a/Old/5c-FileCount_module.psm1 +++ /dev/null @@ -1,12 +0,0 @@ -function Get-FileCount{ - - param([string]$PathName) - - if(Test-Path -Path $PathName){ - $FileCount = (Get-ChildItem $PathName).Length - "$PathName has $FileCount files" | Out-Host - } - else{ - Write-Warning "Path is invalid" - } -} \ No newline at end of file diff --git a/Old/6a-SQLInventory.ps1 b/Old/6a-SQLInventory.ps1 deleted file mode 100644 index cab37e1..0000000 --- a/Old/6a-SQLInventory.ps1 +++ /dev/null @@ -1,15 +0,0 @@ -#SQLInventory example -#first, make sure database objects exist -#.\SQLInventoryObjects.sql - -#import the module -Import-Module SQLInventory -Verbose -Get-command -Module SQLInventory - -#note that the -Verbose tells us the verb it's not happy about and recommends a compliant alternative - -#Open the module code and look at it - - -#run the primary inventory collection function -Get-SQLInventory -invlist @('PICARD','PICARD\WESLEY') -invserv 'PICARD' -invdb 'MSFADMIN' diff --git a/Old/6c-RestoreAutomation.ps1 b/Old/6c-RestoreAutomation.ps1 deleted file mode 100644 index 3f6eae5..0000000 --- a/Old/6c-RestoreAutomation.ps1 +++ /dev/null @@ -1,46 +0,0 @@ -#Restore module -#Download module - https://github.com/MikeFal/PowerShell -import-module RestoreAutomation -Get-Command -Module RestoreAutomation -Get-Help New-Restore -Get-Help New-Restore -Full -Get-Help New-Restore -Examples - -$srv = "PICARD" -$db='dummy2' -New-Restore -dir "\\PICARD\backups\dummy" -server $srv -database $db - -Invoke-Sqlcmd -ServerInstance $srv -Query "if exists (select 1 from sys.databases where name = '$db') drop database $db" -New-Restore -dir "\\PICARD\backups\dummy" -server $srv -database "dummy2" -newdata "C:\DBFiles" -newlog "C:\DBFiles" -Execute - -#Migrate database -Get-Help Sync-DBUsers -$db = "dummy_migration" -$srv = "PICARD\WESLEY" -New-Restore -dir "\\PICARD\backups\dummy" -server 'PICARD\WESLEY' -database $db -newdata "C:\DBFiles\migration" -newlog "C:\DBFiles\migration" -Execute -Invoke-Sqlcmd -ServerInstance $srv -Query "ALTER AUTHORIZATION ON database::[$db] TO [sa]" -Sync-DBUsers -server $srv -database $db - -#Create the logins -$logins=Sync-DBUsers -server $srv -database $db - -foreach($login in $logins.name){ - Invoke-Sqlcmd -ServerInstance $srv -Query "CREATE LOGIN [$login] WITH PASSWORD='P@55w0rd'" -} - -Sync-DBUsers -server $srv -database $db - -#Restore testing -Get-Help Get-DBCCCheckDB -$srv = "PICARD" -$db='CorruptMe2' -Invoke-Sqlcmd -ServerInstance $srv -Query "if exists (select 1 from sys.databases where name = '$db') drop database $db" -New-Restore -server $srv -database $db -dir "\\PICARD\backups\corruptme" -newdata "C:\DBFiles\" -newlog "C:\DBfiles\" -Execute - -Get-DBCCCheckDB -server $srv -database $db - -#messy, let's try that again -Get-DBCCCheckDB -server $srv -database $db | Select level,messagetext,repairlevel | ft -AutoSize - -#If we want the full DBCC check -Get-DBCCCheckDB -server $srv -database $db -Full | where {$_.level -gt 10} | Select messagetext,repairlevel | ft diff --git a/Old/7a-SetupServerCore.ps1 b/Old/7a-SetupServerCore.ps1 deleted file mode 100644 index 558c1c6..0000000 --- a/Old/7a-SetupServerCore.ps1 +++ /dev/null @@ -1,49 +0,0 @@ -<# - Before running this, you should have a server core machine - built and configured with name and networking. -#> -rename-computer 'RIKER' -restart-computer - -#join domain -$pw = 'vanh0uten!42' | convertto-securestring -AsPlainText -Force -$cred = New-Object System.Management.Automation.PSCredential ('SDF\Administrator',$pw) -Add-Computer -DomainName 'SDF.local' -Credential $cred -restart-computer - -#POST SERVER INIT, BASE CONFIGURATION -#configure powershell as default shell - -#This is part of my base image, you would need to do this for your own environment -#Write-Warning "Set Powershell as default shell" -#set-itemproperty "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\WinLogon" shell 'powershell.exe -noexit -command "$psversiontable;import-module ServerManager"' - -#Install .Net Framework -"Install .Net Libraries" -Install-WindowsFeature NET-Framework-Core -Source D:\sources\sxs - -#update firewall -New-NetFirewallRule -DisplayName "Allow SQL Server" -Direction Inbound –LocalPort 1433 -Protocol TCP -Action Allow - -#Create SQL Data directories -Write-Host 'Create default database directories' -New-Item -ItemType Directory -Path C:\DBFiles\Data -Force |ft -New-Item -ItemType Directory -Path C:\DBFiles\Log -Force | ft -New-Item -ItemType Directory -Path C:\DBFiles\TempDB -Force | ft - -#create service account if you want a local account, we will use a domainaccount -#Write-Host "Create Local SQL Server Service Account" -#$account="sqlsvc" -#$pw="5qlp@55w0rd" - -#$comp=[ADSI] "WinNT://$ENV:ComputerName" -#$comp | Get-Member -#$user=$comp.Create("User",$account) -#$user.SetPassword($pw) - -#Set service account so user can't change password and password never expires -#$user.UserFlags = (65536+64) -#$user.SetInfo() - -#install SQL Server -\\HIKARUDC\InstallFiles\SQLServer\SQL2014\setup.exe /CONFIGURATIONFILE='\\HIKARUDC\InstallFiles\SQLServer\\SQL2014_Core.ini' \ No newline at end of file diff --git a/Old/7b-SetupServerCore_DSC.ps1 b/Old/7b-SetupServerCore_DSC.ps1 deleted file mode 100644 index a1b8944..0000000 --- a/Old/7b-SetupServerCore_DSC.ps1 +++ /dev/null @@ -1,12 +0,0 @@ -Write-Warning "Disable the firewall for DEMONSTRATION PURPOSES ONLY" -Set-NetFirewallProfile -Profile * -Enabled False - -#create service account -$account="sqlsvc" -$pw="5qlp@55w0rd" - -$comp=[ADSI] "WinNT://$ENV:ComputerName" -$user=$comp.Create("User",$account) -$user.SetPassword($pw) -$user.UserFlags = (65536+64) -$user.SetInfo() \ No newline at end of file diff --git a/Old/7c-Create_DSC_Configfuration.ps1 b/Old/7c-Create_DSC_Configfuration.ps1 deleted file mode 100644 index 9d4c897..0000000 --- a/Old/7c-Create_DSC_Configfuration.ps1 +++ /dev/null @@ -1,76 +0,0 @@ -Configuration SQLServer{ - param([string[]] $ComputerName) - - Import-DscResource -Module cSQLResources - Import-DscResource -Module xNetworking - - Node $ComputerName { - - File DataDir{ - DestinationPath = 'C:\DBFiles\Data' - Type = 'Directory' - Ensure = 'Present' - } - - File LogDir{ - DestinationPath = 'C:\DBFiles\Log' - Type = 'Directory' - Ensure = 'Present' - } - - File TempDBDir{ - DestinationPath = 'C:\DBFiles\TempDB' - Type = 'Directory' - Ensure = 'Present' - } - - WindowsFeature NETCore{ - Name = 'NET-Framework-Core' - Ensure = 'Present' - IncludeAllSubFeature = $true - Source = 'D:\sources\sxs' - } - - WindowsFeature FC{ - Name = 'Failover-Clustering' - Ensure = 'Present' - Source = 'D:\source\sxs' - } - - xFirewall SQLFW{ - Name = 'SQLServer' - DisplayName = 'SQL Server' - Ensure = 'Present' - Access = 'Allow' - Profile = 'Domain' - Direction = 'Inbound' - LocalPort = '1433' - Protocol = 'TCP' - } - - xFirewall AGFW{ - Name = 'AGEndpoint' - DisplayName = 'Availability Group Endpoint' - Ensure = 'Present' - Access = 'Allow' - Profile = 'Domain' - Direction = 'Inbound' - LocalPort = '5022' - Protocol = 'TCP' - } - - cSQLInstall SQLInstall{ - InstanceName = 'MSSQLSERVER' - InstallPath = '\\HIKARUDC\InstallFiles\SQLServer\SQL2014' - ConfigPath = '\\HIKARUDC\InstallFiles\SQLServer\SQL2014_Core_DSC.ini' - UpdateEnabled = $true - UpdatePath = '\\HIKARUDC\InstallFiles\SQLServer\SQL2014\Updates' - DependsOn = @("[File]DataDir","[File]LogDir","[File]TempDBDir","[WindowsFeature]NETCore") - } - } -} - - -if(test-path .\SQLServer){ Remove-Item .\SQLServer -Recurse -Force } -SQLServer -ComputerName @('RIKER','PICARD') -Start-DscConfiguration .\SQLServer -Wait -Verbose -Force diff --git a/Old/RestoreDummyLogs.sql b/Old/RestoreDummyLogs.sql deleted file mode 100644 index ed2277d..0000000 Binary files a/Old/RestoreDummyLogs.sql and /dev/null differ diff --git a/Old/SQL2014_Core.ini b/Old/SQL2014_Core.ini deleted file mode 100644 index 1c41f22..0000000 --- a/Old/SQL2014_Core.ini +++ /dev/null @@ -1,51 +0,0 @@ -; SQL Server 2014 Configuration File -[OPTIONS] - -; Specifies a Setup work flow, like INSTALL, UNINSTALL, or UPGRADE. This is a required parameter. -ACTION="Install" - -;Set quiet mode ON, send log to command window -QUIET=True -INDICATEPROGRESS=True - -;Updates (CU3) -UPDATEENABLED=True -UPDATESOURCE=\\HIKARU\InstallFiles\SQL2014\Updates - -; Specifies features to install, uninstall, or upgrade. The lists of features include SQLEngine, FullText, Replication, AS, IS, and Conn. -FEATURES=SQLENGINE - -; Specify a default or named instance. MSSQLSERVER is the default instance for non-Express editions and SQLExpress for Express editions. This parameter is required when installing the SQL Server Database Engine, and Analysis Services (AS). -INSTANCENAME="MSSQLSERVER" - -; Specify the Instance ID for the SQL Server features you have specified. SQL Server directory structure, registry structure, and service names will incorporate the instance ID of the SQL Server instance. -INSTANCEID="MSSQLSERVER" - -; Set Mixed Mode security -SECURITYMODE=SQL - -; Windows account(s) to provision as SQL Server system administrators. -; Domain/computer and account should match your environment -SQLSYSADMINACCOUNTS="SDF\mfal" -; Account for SQL Server service: Domain\User or system account. -SQLSVCACCOUNT="SDF\sqlsvc" -SQLSVCPASSWORD="SQLp@55word" - -; Make Agent Service autostart -AGTSVCACCOUNT="SDF\sqlsvc" -AGTSVCPASSWORD="SQLp@55word" -AGTSVCSTARTUPTYPE=Automatic - -SAPASSWORD='SQLP@55word' - -; Enable TCP -TCPENABLED=1 - -; Accept the License agreement to continue with Installation -IAcceptSQLServerLicenseTerms="True" - -; Set install directories -SQLUSERDBDIR="C:\DBFiles\Data" -SQLTEMPDBDIR="C:\DBFiles\TempDB" -SQLTEMPDBLOGDIR="C:\DBFiles\TempDB" -SQLUSERDBLOGDIR="C:\DBFiles\Log" diff --git a/Old/SQL2014_Core_DSC.ini b/Old/SQL2014_Core_DSC.ini deleted file mode 100644 index 0f8877e..0000000 --- a/Old/SQL2014_Core_DSC.ini +++ /dev/null @@ -1,33 +0,0 @@ -; SQL Server 2014 Configuration File -[OPTIONS] - -; Specifies a Setup work flow, like INSTALL, UNINSTALL, or UPGRADE. This is a required parameter. -ACTION="Install" - -;Set quiet mode ON, send log to command window -QUIET=True -INDICATEPROGRESS=True - -; Specifies features to install, uninstall, or upgrade. The lists of features include SQLEngine, FullText, Replication, AS, IS, and Conn. -FEATURES=SQLENGINE - -; Windows account(s) to provision as SQL Server system administrators. -; Domain/computer and account should match your environment -SQLSYSADMINACCOUNTS="SDF\mfal" -; Account for SQL Server service: Domain\User or system account. -SQLSVCACCOUNT="SDF\sqlsvc" -SQLSVCPASSWORD="SQLp@55word" - -; Make Agent Service autostart -AGTSVCACCOUNT="SDF\sqlsvc" -AGTSVCPASSWORD="SQLp@55word" -AGTSVCSTARTUPTYPE=Automatic - -; Enable TCP -TCPENABLED=1 - -; Set install directories -SQLUSERDBDIR="C:\DBFiles\Data" -SQLTEMPDBDIR="C:\DBFiles\TempDB" -SQLTEMPDBLOGDIR="C:\DBFiles\TempDB" -SQLUSERDBLOGDIR="C:\DBFiles\Log" diff --git a/Old/logins.sql b/Old/logins.sql deleted file mode 100644 index 002b085..0000000 Binary files a/Old/logins.sql and /dev/null differ