<#
.Synopsis
   Sets Common Permissions on a Resource Group depending on Ownershiptest
.DESCRIPTION
   Long description
.EXAMPLE
  Set-ITDAzureRMResourceGroupAssignment -Ownership VM -ResourceGroup rg-itd-resourcegroup-tst
.EXAMPLE
   Set-ITDAzureRMResourceGroupAssignment -Ownership Network -ResourceGroup rg-itd-netresourcegroup-tst
#>
function Set-ITDAzureRMResourceGroupAssignment
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true, Position=0)]
        [String]
        $Ownership,

        # Param2 help description
        [Parameter(Mandatory=$true,Position=1)]
        [string]
        $ResourceGroup
    )

    Begin
    {
    $Tenant = (Get-AzureRMContext).Environment.Name
    }
    Process
    {
    If ($Ownership -eq "VM"){
        If($Tenant -eq "AzureUSGovernment")
        {
            $ADGroupOperator = Get-AzureRMADGroup -SearchString "ITD-MAG-VM-Operator"
            $ADGroupContributor = Get-AzureRMADGroup -SearchString "ITD-MAG-VM-Contributor"
        }
        Elseif($Tenant -eq "AzureCloud")
        {
            $ADGroupOperator = Get-AzureRMADGroup -SearchString "ITD-MAC-VM-Operator"
            $ADGroupContributor = Get-AzureRMADGroup -SearchString "ITD-MAC-VM-Contributor"
        }     
        New-AzureRMRoleAssignment -ObjectID $ADGroupOperator.Id.ToString() -RoleDefinitionName "ITD-VM-Operator"  -ResourceGroup $ResourceGroup
        New-AzureRMRoleAssignment -ObjectID $ADGroupContributor.Id.ToString() -RoleDefinitionName "ITD-VM-Contributor"  -ResourceGroup $ResourceGroup
        }

        If ($Ownership -eq "Network"){
            If($Tenant -eq "AzureUSGovernment")
            {
                $ADGroupOperator = Get-AzureRMADGroup -SearchString "ITD-MAG-Network-Operator"
                $ADGroupContributor = Get-AzureRMADGroup -SearchString "ITD-MAG-Network-Contributor"
            }
            Elseif($Tenant -eq "AzureCloud")
            {
                $ADGroupOperator = Get-AzureRMADGroup -SearchString "ITD-MAC-Network-Operator"
                $ADGroupContributor = Get-AzureRMADGroup -SearchString "ITD-MAC-Network-Contributor"
            }     
            New-AzureRMRoleAssignment -ObjectID $ADGroupOperator.Id.ToString() -RoleDefinitionName "ITD-VM-Operator"  -ResourceGroup $ResourceGroup
            New-AzureRMRoleAssignment -ObjectID $ADGroupContributor.Id.ToString() -RoleDefinitionName "ITD-VM-Contributor"  -ResourceGroup $ResourceGroup
            }
    }
    End
    {
    }
}


<#
.Synopsis
   Gets all Azure IP's Across MAC and MAG and outputs to text files
.DESCRIPTION
   Long description
.EXAMPLE
   Get-ITDAzureRMIPs -OutputPath "C:\temp"
.EXAMPLE
   Example2
#>
function Get-ITDAzureRMIPs
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true, Position=0)]
        [String]
        $OutputPath
    )

    Begin
    {
        $WindowsIPs = ""
        $LinuxIPs = ""
        $OutFileWin = $OutputPath + "\AzureWin.txt"
        $OutFileLin = $OutputPath + "\AzureLin.txt"
    }
    Process
    {
        Login-AzureRMAccount

        $Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
        foreach($subscription in $subscriptions)
        {
            Set-AzureRMContext -SubscriptionObject $subscription
            $WindowsVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Windows"}
            $LinuxVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Linux" -and $_.StorageProfile.ImageReference.Publisher -ne "infoblox" -and $_.StorageProfile.ImageReference.Publisher -ne "paloaltonetworks" -and $_.StorageProfile.ImageReference.Publisher -ne "juniper-networks"}
            $nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}

            foreach($vm in $WindowsVMs)
            {
                    $vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
                    foreach($vmnicinterface in $vmnicinterfaces)
                    {
                        $nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
                        $privateip = $nic.IpConfigurations | Select PrivateIPAddress
            
                        If($privateip.count -gt 1)
                        {
                            foreach($private in $privateip)
                            {
                                $WindowsIPs += $private.privateIPAddress + "`n"
                            }
                        }
                        elseIf($privateip.privateIPAddress -ne $null)
                            {
                                $WindowsIPs += $privateip.privateIPAddress + "`n"
                            }
                    }
            }

            foreach($vm in $LinuxVMs)
            {
                $vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
                foreach($vmnicinterface in $vmnicinterfaces)
                {
                    $nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
                    $privateip = $nic.IpConfigurations | Select PrivateIPAddress
            
                    If($privateip.count -gt 1)
                    {
                        foreach($private in $privateip)
                        {
                            $LinuxIPs += $private.privateIPAddress + "`n"
                        }
                    }
                    elseif($privateip.privateIPAddress -ne $null)
                    {
                        $LinuxIps += $privateip.privateIPAddress + "`n"
                    }
                }
            }
        }

        Login-AzureRMAccount -EnvironmentName AzureUSGovernment

        $Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
        foreach($subscription in $subscriptions)
        {
            Set-AzureRMContext -SubscriptionObject $subscription
            $WindowsVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Windows"}
            $LinuxVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Linux" -and $_.StorageProfile.ImageReference.Publisher -ne "infoblox" -and $_.StorageProfile.ImageReference.Publisher -ne "paloaltonetworks" -and $_.StorageProfile.ImageReference.Publisher -ne "juniper-networks"}
            $nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}

            foreach($vm in $WindowsVMs)
            {
                $vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
                foreach($vmnicinterface in $vmnicinterfaces)
                {
                    $nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
                    $privateip = $nic.IpConfigurations | Select PrivateIPAddress
                    If($privateip.count -gt 1)
                    {
                        foreach($private in $privateip)
                        {
                            $WindowsIPs += $private.privateIPAddress + "`n"
                        }
                    }
                    elseIf($privateip.privateIPAddress -ne $null)
                    {
                        $WindowsIPs += $privateip.privateIPAddress + "`n"
                    }
                }
            }

            foreach($vm in $LinuxVMs)
            {
                $vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
                foreach($vmnicinterface in $vmnicinterfaces)
                {
                    $nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
                    $privateip = $nic.IpConfigurations | Select PrivateIPAddress
            
                    If($privateip.count -gt 1)
                    {
                        foreach($private in $privateip)
                        {
                            $LinuxIPs += $private.privateIPAddress + "`n"
                        }
                    }
                    elseif($privateip.privateIPAddress -ne $null)
                    {
                        $LinuxIps += $privateip.privateIPAddress + "`n"
                    }
                }
            }
        }

        If ($WindowsIPs -ne "") {$WindowsIPs | Out-File $OutFileWin -Encoding ASCII -NoNewline}
        If ($LinuxIPs -ne "") {$LinuxIPs | Out-File $OutFileLin -Encoding ASCII -NoNewline}
    }
    End
    {
    }
}


function Set-ITDAzureRMResourceGroupTags
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        # Resouce Group
        [String]
        $ResourceGroup,

        # Tag Hash Table
        [HashTable]
        $TagHashTable,

        # Input File
        [String]
        $InputFile
    )
    Begin
    {          
    }
    Process
    {
        If($InputFile)
        {
            $filetable = Import-CSV -Path $InputFile
            foreach($record in $filetable)
            {
                $TagHashTable = @{}
                $TagHashTable.Add("Environment",$record.Environment)
                $TagHashTable.Add("Platform",$record.Platform)
                $TagHashTable.Add("RequestID",$record.RequestID)
                $TagHashTable.Add("Division",$record.Division)
                $TagHashTable.Add("ApplicationName",$record.ApplicationName)
                $TagHashTable.Add("ChargeCode",$record.ChargeCode)
                $TagHashTable.Add("Department",$record.Department)
            
                Set-AzureRmContext $record.Subscription
                Set-ITDAzureRMResourceGroupTags -ResourceGroup $record.ResourceGroup -TagHashTable $TagHashTable
            }
            Return       
        }
        
        
        
        #Get Current Tags from Resource Group
        $GroupTags = (Get-AzureRmResourceGroup -Name $ResourceGroup).Tags
    
        #Identify Duplicate Tags.  Remove Duplicates from Original Tags in Case of Conflict
        $DuplicateItems = $GroupTags.Keys | Where-Object {$TagHashTable.ContainsKey($_)}
            If ($DuplicateItems) {
                ForEach ($DuplicateKey in $DuplicateItems){
                    $GroupTags.Remove($DuplicateKey)
                }
            }
        
        #Merge Hashtables and Write Table back to Resource Group
        $GroupTags += $TagHashTable
        Set-AzureRmResourceGroup -Name $ResourceGroup -Tag $GroupTags
        
        #Get All Resources in the Resource Group
        $Resources = Get-AzureRmResource | Where-Object {$_.ResourceGroupName -eq $ResourceGroup -and $_.ResourceType -notmatch "Microsoft.Compute/virtualMachines/extensions"}
        ForEach ($Resource in $Resources){
            $ResourceTags = $Resource.Tags
            
            #Identify Duplicate Tags.  Remove Duplicates from Original Tags in Case of Conflict
            $DuplicateItems = $ResourceTags.Keys | Where-Object {$TagHashTable.ContainsKey($_)}
                If ($DuplicateItems) {
                    ForEach ($DuplicateKey in $DuplicateItems){
                        $ResourceTags.Remove($DuplicateKey)
                    }
                }
        
            #Merge Hashtables  and Write Table back to Resource
            $ResourceTags += $TagHashTable
            Set-AzureRMResource -ResourceID $Resource.ResourceID -Tag $ResourceTags -Confirm:$false -Force

        }          
    }
    End
    {
    }
}

function Set-ITDAzureRMResourceGroupTagsRefresh
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        # Resouce Group
        [String]
        $ResourceGroup
    )
    Begin
    {          
        $TagHashTable = @{}
        $TagHashTable = (Get-AzureRMResourceGroup -Name $ResourceGroup ).Tags
    }
    Process
    {
        Set-ITDAzureRMResourceGroupTags -ResourceGroup $ResourceGroup -TagHashTable $TagHashTable           
    }
    End
    {
    }
}


function New-ITDAzureRMPolicyDefinition
{
    [OutputType([int])]
    Param
    (
        # Resource Group
        [Parameter(Mandatory=$true, Position=0)]
        [Array]
        $Environments,

        # Policy Name Prefix
        [Parameter(Mandatory=$true, Position=1)]
        [String]
        $prefix,

        # Policy Name Suffix
        [Parameter(Mandatory=$true, Position=2)]
        [String]
        $suffix,

        # Policy in String Format (If...Then Components)
        [Parameter(Mandatory=$true,Position=3)]
        [String]
        $Policy
    
    )
    Begin
    {          
    }
    Process
    {
        Foreach ($environment in $Environments){
            Set-AzureRMContext $environment
            $policyname = $prefix + $environment + $suffix
            New-AzureRmPolicyDefinition -Name $policyname -Policy $Policy
            }         
    }
    End
    {
    }
}

function Find-ITDAzureRMUntaggedResources
{
    [OutputType([int])]
    Param
    (
        # Resource Group
        [Parameter(Mandatory=$false, Position=0)]
        [String]
        $TagName
    )
    Begin
    {
        $subscriptions = @()
        $untaggedresources = @()          
    }
    Process
    {
        #$subscriptions = Get-AzureRMSubscription | WHere-Object {$_.name -ne "sandbox"}
        $subscriptions = Get-AzureRMSubscription
        
        Foreach ($subscription in $subscriptions){
            Set-AzureRMContext $subscription
            $resources = Get-AzureRMResource 
            ForEach ($resource in $resources){
                If ($resource.tags -ne $null){
                    If (($resource.tags.contains("Department") -eq $false) -or ($resource.tags.contains("ApplicationName") -eq $false) -or ($resource.tags.contains("Environment") -eq $false) -or ($resource.tags.contains("RequestID") -eq $false)){
                        $untaggedresources += $resource
                    }
                }
                Else {
                   $untaggedresources += $resource
                } 
            }
        }  
        $untaggedresources | Select Name, ResourceGroupName, SubscriptionID | Sort-Object SubscriptionID, ResourceGroupname, Name | Format-Table
    }
    End
    {
    }
}

<#
.Synopsis
   Creates an Azure VM.
.DESCRIPTION
   Long description
.EXAMPLE
  New-ITDAzureRMVM -VMName itdcdtest -VMSubscription npd01 -VMEnvironment tst -VMOwner shared -VMFunction cdtesting -VMSize Standard_A2 -VMOS Windows -VMPublisher MicrosoftWindowsServer -VMOffer WindowsServer -VMSku 2016-Datacenter -VMVNetName vnet-tst-npd01-001 -VMSubnet "sn-10.21.20.0_28" -VMLocation centralUS -VMIP "10.21.20.10"
.EXAMPLE
   
#>
function New-ITDAzureRMVM
{
    [CmdletBinding()]
    Param
    (
        # VM Computer Name (FQDN)
        [Parameter(Mandatory=$true, Position=0)]
        [String]
        $VMFQDN,        
        
        # VM Subscription (tst,prd,dr)
        [Parameter(Mandatory=$true)]
        [string]
        $VMSubscription,

        # Environment (tst,prd,dr)
        [Parameter(Mandatory=$true)]
        [string]
        $VMEnvironment,

        # Owner (infra,shared,ITD,DHS,etc)
        [Parameter(Mandatory=$true)]
        [string]
        $VMOwner,

        # Function (testdc, POC, etc)
        [Parameter(Mandatory=$true)]
        [string]
        $VMFunction,

        #[Parameter(Mandatory=$true)]
        [string]
        $ResourceGroupIndexNumber,

        # Azure VM Size 
        [Parameter(Mandatory=$true)]
        [string]
        $VMSize,

        # Azure OS (Windows or Linux)
        [Parameter(Mandatory=$true)]
        [string]
        $VMOS,

        # Availability Set
        [switch]
        $VMAS,

        # Availability Set Tier
        [string]
        $VMASTier,

        # Availability Zone
        [ValidateSet(1,2,3)]
        [int]
        $VMAvailZone,
                
        # Azure Publisher
        [string]
        $VMPublisher,

        # Azure Offer
        [string]
        $VMOffer,

        # Azure Sku
        [string]
        $VMSku,

        # Azure vNet
        [Parameter(Mandatory=$true)]
        [string]
        $VMVNetName,

        # Azure Subnet
        [Parameter(Mandatory=$true)]
        [string]
        $VMSubnet,

        # Azure Location
        [Parameter(Mandatory=$true)]
        [string]
        $VMLocation,

        # Azure Private IP
        [Parameter(Mandatory=$true)]
        [string]
        $VMIP,

        [Parameter(Mandatory=$true)]
        [PSCredential]
        $VMCredential
    )
    Begin
    {
        $VMName = $VMFQDN.Split('.')[0]   
        $VMIndexNumber = "001"
        $VMIPConfigName = "ipconfig-$VMName-$VMEnvironment"
        $VMNicName = "nic-$VMName-$VMEnvironment" ######
        $VMObjectName = "vm-$VMName-$VMEnvironment"
        $ResourceGroup = "rg-$VMOwner-$VMFunction-$VMEnvironment"
        If($ResourceGroupIndexNumber){$ResourceGroup = $ResourceGroup + "-$ResourceGroupIndexNumber"}
        $VMDiagStorageAcct = "sa" + $VMOwner + $VMFunction + "diag" + $VMEnvironment
        $VMOSDiskName = "vm-$VMName-os-$VMEnvironment"
        
        If($VMASTier)
        {
            $VMASName = "as-$VMOwner-$VMFunction-$VMASTier-$VMEnvironment"
        }
        Else
        {
            $VMASName = "as-$VMOwner-$VMFunction-$VMEnvironment"
        }

        $ResGroupExist = ""

        Write-Verbose "Checking Storage Account Length"
        If (($VmDiagStorageAcct.Length) -gt 24){
            Write-Verbose "Storage Account Length is too long.  Truncating function...."
            $TruncateCharacters = $VmDiagStorageAcct.Length - 24
            $ShortVMFunction = $VMFunction.Substring(0, ($VMFunction.length) - $TruncateCharacters)
            $VMDiagStorageAcct = "sa" + $VMOwner + $ShortVMFunction + "diag" + $VMEnvironment
        }

        If (($VmDiagStorageAcct.Length) -gt 24){
            Write-Verbose "Storage Account Length is too long after truncating.  Terminating Build"
            Return
        }

        Write-Verbose "Verifying Applicable Inputs are Lowercase"
            $VMIPConfigName = $VMIPConfigName.ToLower()
            $VMNicName = $VMNicName.ToLower()
            $VMObjectName = $VMObjectName.ToLower()
            $ResourceGroup = $ResourceGroup.ToLower()
            $VMDiagStorageAcct = $VMDiagStorageAcct.ToLower()
            $VMOSDiskName = $VMOSDiskName.ToLower()
    }
    Process
    {
        Set-AzureRMContext $VMSubscription
        
        Write-Verbose "Creating Resource Group if it doesn't exist"      
        $ResGroupExist = Get-AzureRMResourceGroup -Name $ResourceGroup -ErrorAction SilentlyContinue

        If (!($ResGroupExist)) 
        {
            New-AzureRmResourceGroup -Name $ResourceGroup -Location $VMLocation
        }
        
        Write-Verbose "Checking Storage Account Availability in Subscription"        
        If (!(Get-AzureRmStorageAccount | Where-Object {$_.StorageAccountName -eq $VMDiagStorageAcct}))        
        {
            If ((Get-AzureRmStorageAccountNameAvailability -Name $VMDiagStorageAcct).NameAvailable -eq $True) 
            {
                
                New-AzureRmStorageAccount -Name $VMDiagStorageAcct -Location $VMLocation -ResourceGroupName $ResourceGroup -SkuName "Standard_LRS" -EnableHttpsTrafficOnly $true
                #Start-Sleep -Seconds 5
                Get-AzureRmStorageAccount -ResourceGroupName $ResourceGroup -Name $VMDiagStorageAcct | Update-AzureRmStorageAccountNetworkRuleSet -DefaultAction Deny -Bypass None
                #Update-AzureRmStorageAccountNetworkRuleSet -ResourceGroupName $ResourceGroup -Name $VMDiagStorageAcct -DefaultAction Deny -Bypass None
                Add-AzureRmStorageAccountNetworkRule -ResourceGroupName $ResourceGroup -AccountName $VMDiagStorageAcct -IPAddressOrRange "165.234.248.3"
            }
            Else 
            {
                Write-Verbose "Storage Account already exists.  Re-run with a valid storage account"
                Return    
            }  
        }

        Write-Verbose "Evaluating Availability Set"
        If($VMAS)
        {
            Write-Verbose "Checking for existing Availability Set"
            $VMASExist = Get-AzureRMAvailabilitySet -ResourceGroupName $ResourceGroup -Name $VMASName -ErrorAction SilentlyContinue
            If($VMASExisting)
            {
                $VMASID = $VMASExist.id    
            }
            Else
            {
                New-AzureRMAvailabilitySet -ResourceGroupName $ResourceGroup -Name $VMASName -Location $VMLocation -PlatformFaultDomainCount 3 -PlatformUpdateDomainCount 5 -Sku Aligned
                $VMASID = (Get-AzureRMAvailabilitySet -ResourceGroupName $ResourceGroup -Name $VMASName).id
            }
        }

        Write-Verbose "Preparing Network Config"
        $VNet = (Get-AzureRmVirtualNetwork | where {$_.Name -eq $VMVNetName})
        $VNetID = $VNet.id
        $Subnet = ($VNet.Subnets | where {$_.Name -eq $VMSubnet})
        $SubnetName = $Subnet.name
        $SubnetID = $Subnet.id
          
        Write-Verbose "Creating IPConfig and NIC"
        $IPConfig = New-AzureRmNetworkInterfaceIpConfig -Name $VMIPConfigName -PrivateIpAddress $VMIP -PrivateIpAddressVersion IPv4 -Subnet $Subnet
        $VMNIC = New-AzureRmNetworkInterface -IpConfigurationName $IPConfig -Location $VMLocation -Name $VMNICName -ResourceGroupName $ResourceGroup -SubnetId $SubnetID
        $VMNIC.IpConfigurations[0].PrivateIpAllocationMethod = "Static"
        $VMNIC.IpConfigurations[0].PrivateIpAddress = $VMIP
        Set-AzureRmNetworkInterface -NetworkInterface $VMNIC

        Write-Verbose "Building VM Config"
        If($VMAS)
        {
            $vmConfig = New-AzureRmVMConfig -VMName $VMObjectName -VMSize $VMSize -AvailabilitySetId $VMASID
        }
        Else
        {
            If($VMAvailZone)
            {
                Write-Verbose "AvailZone $VMAvailZone"
                $vmConfigParams = @{
                    VMName = $VMObjectName
                    VMSize = $VMSize
                    Zone = $VMAvailZone
                }
            }
            Else
            {
                Write-Verbose "No AvailZone"
                $vmConfigParams = @{
                    VMName = $VMObjectName
                    VMSize = $VMSize
                }
            }
            #$vmConfig = New-AzureRmVMConfig -VMName $VMObjectName -VMSize $VMSize
            $vmConfig = New-AzureRmVMConfig @vmConfigParams
        }

        
        
        $vmConfig | Set-AzureRmVMOSDisk -Name $VMOSDiskName -CreateOption FromImage
        If($VMOS -eq "Windows")
        {
            $vmConfig | Set-AzureRmVMOperatingSystem -Windows -ComputerName $VMName -Credential $VMCredential
            $vmConfig | Set-AzureRmVMSourceImage -PublisherName $VMPublisher -Offer $VMOffer -Skus $VMSku -Version latest
        }
        If($VMOS -eq "Linux")
        {
            $vmConfig | Set-AzureRmVMOperatingSystem -Linux -ComputerName $VMFQDN -Credential $VMCredential
            Switch($VMSubscription)
            {
                #"npd01" {$vmConfig | Set-AzureRmVMSourceImage -Id "/subscriptions/76297098-764c-43de-8525-c9fda1b237be/resourceGroups/rg-infra-templates-tst-001/providers/Microsoft.Compute/images/vm-rhel74template-prd-001"}
                #"infra01" {$vmConfig | Set-AzureRmVMSourceImage -Id "/subscriptions/e53aa0c7-824d-40a2-b420-4ab77b1051d2/resourceGroups/rg-infra-templates-prd-001/providers/Microsoft.Compute/images/vm-rhel74template-prd-001"}
                #"prd01" {$vmConfig | Set-AzureRmVMSourceImage -Id "/subscriptions/437b2bfa-850e-4464-b6c2-38a68cda7c69/resourceGroups/rg-infra-templates-prd-002/providers/Microsoft.Compute/images/vm-rhel74template-prd-002"}

                "npd01"   {$vmConfig | Set-AzureRmVMSourceImage -Id "/subscriptions/76297098-764c-43de-8525-c9fda1b237be/resourceGroups/rg-infra-templates-tst-001/providers/Microsoft.Compute/images/vm-rhel74template-prd-103"}
                "infra01" {$vmConfig | Set-AzureRmVMSourceImage -Id "/subscriptions/e53aa0c7-824d-40a2-b420-4ab77b1051d2/resourceGroups/rg-infra-templates-prd-001/providers/Microsoft.Compute/images/vm-rhel74template-prd-403"}
                "prd01"   {$vmConfig | Set-AzureRmVMSourceImage -Id "/subscriptions/437b2bfa-850e-4464-b6c2-38a68cda7c69/resourceGroups/rg-infra-templates-prd-002/providers/Microsoft.Compute/images/vm-rhel74template-prd-003"}
            }
        }
        
        $vmConfig | Add-AzureRmVMNetworkInterface -Id $VMNIC.ID
        $vmConfig | Set-AzureRmVMBootDiagnostics -Enable -ResourceGroupName $ResourceGroup -StorageAccountName $VMDiagStorageAcct
          
        Write-Verbose "Creating VM"
        New-AzureRMVM -VM $vmConfig -ResourceGroupName $resourceGroup -Location $VMLocation -DisableBginfoExtension -AsJob

         
    }
    End
    {
    }
}

function Remove-ITDAzureRMResourceGroupTags
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
       # Input File
        [Parameter(Mandatory=$true)]
        [String]
        $InputFile,

        # Azure Tag to Remove
        [Parameter(Mandatory=$true)]
        [string]
        $RemoveTag
    )
    Begin
    {          
    }
    Process
    {
        If($InputFile)
        {
            $filetable = Import-CSV -Path $InputFile
            foreach($record in $filetable)
            {
                $ResTag = $record.ResourceGroup
                $SubTag = $record.Subscription
                
                Set-AzureRmContext $SubTag
                $GroupTags = (Get-AzureRmResourceGroup -Name $ResTag).Tags
                $GroupTags.Remove($RemoveTag)
                Set-AzureRmResourceGroup -Name $ResTag -Tag $GroupTags

                $Resources = Get-AzureRmResource | Where-Object {$_.ResourceGroupName -eq $ResTag}
                ForEach ($Resource in $Resources)
                {
                    $ResourceTags = $Resource.Tags
                    $GroupTags.Remove($RemoveTag)
                    Set-AzureRMResource -ResourceID $Resource.ResourceID -Tag $ResourceTags -Confirm:$false -Force
                }
            }
            Return       
        }
                
    }
    End
    {
    }
}

<#
.Synopsis
   Create new Azure data disk, and attach to the specified VM
.DESCRIPTION
   Create new Azure data disk, and attach to the specified VM.  
    - Determines ResourceGroup where disk will be created, the name of the disk, and the LUN ID the disk will use.
    - SizeGB must be unique for each disk attached to a virtual machine.  If the SizeGB parameter is not unique, new size will be automatically determined.
.EXAMPLE
   Add-ITDAzureRMNewDataDisk -VMName vm-itdvm-tst -SizeGB 32
#>
function Add-ITDAzureRMNewDataDisk
{
    [CmdletBinding()]
    Param
    (
        [string]
        $VMName,

        [int[]]
        $SizeGB
    )

    Begin
    {
        $search=@()
        $Hostname=$VMName.split('-')[1]
        $Environment=$VMName.split('-')[2]

        Get-AzureRmSubscription | ForEach-Object{
            $Subscription=$_
            Set-AzureRmContext $_ | Out-Null
            $search += Get-AzureRmVM | Where-Object Name -eq $VMName | select *,@{n='SubscriptionName';e={$Subscription.Name}}
        }
    }
    Process
    {
        If($search.count -eq 1)
        {
            Set-AzureRmContext $search.SubscriptionName
            $ResourceGroup = $search.ResourceGroupName.ToLower()
            $Location = (Get-AzureRmResourceGroup -Name $ResourceGroup).Location
            $VM = Get-AzureRmVM -Name $VMName -ResourceGroupName $ResourceGroup
            $Zone=$VM.Zones
    

            ForEach($Size in $SizeGB)
            {
                $ExistingDisks = @($VM.StorageProfile.DataDisks | select *,@{n='ItdId';e={[int]($_.Name -replace "vm-$hostname-app-$environment-")}})
    
                $NewDiskItdIdInt = ($ExistingDisks | Sort-Object ItdId -Descending | select -First 1).ItdId + 1
                $NewDiskItdIdStr = $NewDiskItdIdInt.ToString("000")
                $NewDiskName="vm-$Hostname-app-$Environment-$NewDiskItdIdStr" #vm-itduc4p1-app-tst-001
        
                $LunID = ($ExistingDisks | Sort-Object Lun -Descending | Select-Object -First 1).Lun + 1
    
                $count=0
                If($ExistingDisks)
                {
                    while ($Size -match $ExistingDisks.DiskSizeGB)
                    {
                        $count++
                        Write-Warning "SizeGB: $Size, Count: $count"
                        If($count -ge 11)
                        {
                            Write-Error "Disk size not available" -ErrorAction Stop
                        }
                        Else
                        {
                            $Size = $Size - 1
                        }
                    }
                }
    
                Write-Warning "SizeGB: $Size, Count: $count"
    
                $AzureRmDiskConfigParams=@{
                    DiskSizeGB = $Size
                    Location = $Location
                    CreateOption = "Empty"
                    SkuName = "Premium_LRS"
                }

                If($Zone)
                {
                    Write-Verbose "VM is located in Zone $Zone"
                    $AzureRmDiskConfigParams += @{Zone = $Zone}
                }
                #$DiskConfig = New-AzureRmDiskConfig -DiskSizeGB $Size -Location $Location -CreateOption Empty -SkuName Premium_LRS
                $DiskConfig = New-AzureRmDiskConfig @AzureRmDiskConfigParams

                If(!(Get-AzureRmDisk -ResourceGroupName $ResourceGroup -DiskName $NewDiskName -ErrorAction SilentlyContinue))
                {
                    $NewDisk = New-AzureRmDisk -DiskName $NewDiskName -Disk $DiskConfig -ResourceGroupName $ResourceGroup
            
                    $VM = Add-AzureRmVMDataDisk -Name $NewDiskName -CreateOption Attach -ManagedDiskId $NewDisk.Id -VM $VM -Lun $LunID -Caching ReadOnly
                    Update-AzureRmVM -VM $VM -ResourceGroupName $ResourceGroup -AsJob
                }   
            }           
        }
        Else
        {
            Write-Error "Search count invalid" -ErrorAction SilentlyContinue
        }
    }
    End
    {
    }
}

<#
.SYNOPSIS
    Provision Windows or RHEL VM
.DESCRIPTION
    Create Azure IaaS VM, to ITD standards:
    *** Requires resource group to be created before running
    *** Required DNS record for FQDN.
    - Create Storage Account for Resource Group if missing
    - Create VM
        - Scaled to hardware specifications, B-class for tst, D-class for prd
            -Size parameter exists if above restrictions must be overridden
        - NIC created, IP pulled from DNS
        - Auto decide VLAN/subnet based on Environment parameter
        - Operating system chosen by user
    - Auto generate PasswordState record (ITDActiveDirectory module required) with GeneratePassword parameter
        - Utilize VMCredential parameter to set local administrator (itdadmin) password
.EXAMPLE
    New-ITDAzureVM -ComputerName itddc20.nd.gov -CPU 2 -Memory 8 -AppName "Infra-Active Directory" -Environment "prd" -OperatingSystem WS2012R2 -GeneratePassword
.EXAMPLE
    New-ITDAzureVM -ComputerName itddc21.nd.gov -CPU 2 -Memory 8 -AppName "Infra-Active Directory" -Environment "prd" -OperatingSystem WS2012R2 -VMCredential (Get-Credential)
#>
function New-ITDAzureVM
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true)]
        [string]       
        $ComputerName,

        [Parameter(Mandatory=$true)]
        [int]
        $CPU,

        [Parameter(Mandatory=$true)]
        [int]
        $Memory,

        [Parameter(Mandatory=$true)]
        [string]
        $AppName,

        [Parameter(Mandatory=$true)]
        [ValidateSet("tst","prd")]
        [string]
        $Environment,

        [string]
        $ResourceGroupIndex,

        [Parameter(Mandatory=$true)]
        [ValidateSet("WS2012R2","WS2016","WS2019","WS2022","W10v1803","W10v1809","RHEL7.4")]
        [string]
        $OperatingSystem,

        [ValidateSet(1,2,3)]
        [int]
        $AvailZone,
        
        [Parameter(ParameterSetName="PasswordGenerate")]
        [switch]
        $GeneratePassword,

        [Parameter(ParameterSetName="PasswordEnter")]
        [PSCredential]
        $VMCredential

        #[string]
        #$VMSizeOverride,

        #[ValidateSet('infra01','npd01','prd01')]
        #[string]
        #$SubscriptionOverride
    )
    
    begin
    {
        $location="centralus"
        $username = "itdadmin"

        $VMOwner = $AppName.split('-')[0].ToLower()
        $VMFunction = (($AppName -replace "$VMOwner-") -replace "-").ToLower() -replace " "
        $Name=$ComputerName.Split('.')[0]
        $IPAddress = (Resolve-DnsName -Name $ComputerName -ErrorAction Stop).IpAddress    
        $ResourceGroup = "rg-$VMOwner-$VMFunction-$Environment"
        If($ResourceGroupIndex){$ResourceGroup = $ResourceGroup + "-$ResourceGroupIndex"}
        $VMName = "vm-$Name-$Environment"
    }
    
    process
    {
        
        switch ($Environment)
        {
            tst 
            {
                $VMSizeFilter="*_B*s*"
                $Subscription = "npd01"
                $VNet="vnet-npd01-001"
                $VNetSubnet="sn-shared-zerotrust-npd-10.21.8.0_22"
            }
            prd
            {
                $VMSizeFilter="*_D*s*"
                $Subscription = "prd01"
                $VNet="vnet-prd01-001"
                $VnetSubnet="sn-shared-zerotrust-prd-10.21.12.0_22"
            }
            Default
            {
                Write-Error "Environment failed" -ErrorAction Stop
            }
        }

        switch ($OperatingSystem)
        {
            'WS2012R2'
            {
                $VMOS = "Windows"
                $Publisher = "MicrosoftWindowsServer"
                $Offer = "WindowsServer"
                $sku = "2012-R2-Datacenter"
                $PSList = "CSRC"
            }
            'WS2016'
            {
                $VMOS = "Windows"
                $Publisher = "MicrosoftWindowsServer"
                $Offer = "WindowsServer"
                $sku = "2016-Datacenter"
                $PSList = "CSRC"
            }
            'WS2019'
            {
                $VMOS = "Windows"
                $Publisher = "MicrosoftWindowsServer"
                $Offer = "WindowsServer"
                $sku = "2019-Datacenter"
                $PSList = "CSRC"
            }
            'WS2022'
            {
                $VMOS = "Windows"
                $Publisher = "MicrosoftWindowsServer"
                $Offer = "WindowsServer"
                $sku = "2022-Datacenter"
                $PSList = "CSRC"
            }
            'W10v1803'
            {
                $VMOS = "Windows"
                $Publisher = "MicrosoftWindowsDesktop"
                $Offer = "Windows-10"
                $sku = "rs4-pro"
                $PSList = "CSRC"
            }
            'W10v1809'
            {
                Write-Error "W10v1809 not available" -ErrorAction Stop
                $VMOS = "Windows"
                $Publisher = "MicrosoftWindowsDesktop"
                $Offer = "Windows-10"
                $sku = "rs5-pro"
                $PSList = "CSRC"
            }
            'RHEL7.4'
            {
                $VMOS = "Linux"
                $Publisher = $null
                $Offer = $null
                $sku = $null
                $PSList = "Linux"
            }
        }

        If ($GeneratePassword)
        {
            Write-Verbose "GeneratePassword true"
            try
            {
                $TimeStamp = Get-Date -UFormat "%Y%m%d-%H%M%S"
                Write-Warning "[$ComputerName]:$TimeStamp - Password generation "
                #$password = ConvertTo-SecureString (New-ITDLocalAdminPasswordstateRecord -ComputerName $ComputerName -Azure -PasswordstateList $PSList -Credential $AdminCred).Password -AsPlainText -Force
                $password = ConvertTo-SecureString (New-ITDPasswordstateRecord -Title $ComputerName -Description "Local Admin" -PSList $PSList -GeneratePassword -Username itdadmin -ReturnPassword).Password -AsPlainText -Force
            }
            catch
            {
                Write-Error "GeneratePassword failed, process manually" -ErrorAction Stop
            }
        }
        Else
        {
            Write-Verbose "GeneratePassword false"
            $password = $VMCredential.Password
        }
        
        $VMCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,$password

        $VMSize = Get-AzureRmVMSize -Location $location | `
            Where-Object Name -Like "$VMSizeFilter" | `
            Where-Object {$_.NumberOfCores -ge $CPU -and $_.MemoryInMB -ge ($Memory * 1024)*0.5 } | `
            Where-Object Name -NotMatch "_Promo" | `
            Sort-Object NumberOfCores,MemoryInMB | `
            Select-Object -First 1

        If($SubscriptionOverride)
        {
            $Subscription = $SubscriptionOverride
        }
        If($VMSizeOverride)
        {
            $VMSize = Get-AzureRmVMSize -Location $location | `
                Where-Object Name -Like $VMSizeOverride
        }

        $NewITDAzureRMVMParams=@{
            VMFQDN = $ComputerName
            VMSubscription = $Subscription
            VMEnvironment = $Environment
            VMOwner = $VMOwner
            VMFunction = $VMFunction
            VMSize = $VMSize.Name
            VMOS = $VMOS
            VMPublisher = $Publisher
            VMOffer = $Offer
            VMSku = $sku
            VMVnetName = $VNet
            VMSubnet = $VNetSubnet
            VMLocation = $location
            VMIP = $IPAddress
            VMCredential = $VMCredential
        }

        If($AvailZone){$NewITDAzureRMVMParams += @{VMAvailZone = $AvailZone}}
        If($ResourceGroupIndex){$NewITDAzureRMVMParams += @{$ResourceGroupIndexNumber = $ResourceGroupIndex}}
        <#
        Write-Warning $NewITDAzureRMVMParams.VMFQDN
        Write-Warning $NewITDAzureRMVMParams.VMSubscription
        Write-Warning $NewITDAzureRMVMParams.VMEnvironment
        Write-Warning $NewITDAzureRMVMParams.VMOwner
        Write-Warning $NewITDAzureRMVMParams.VMFunction
        Write-Warning $NewITDAzureRMVMParams.VMSize
        Write-Warning $NewITDAzureRMVMParams.VMOS
        Write-Warning $NewITDAzureRMVMParams.VMPublisher
        Write-Warning $NewITDAzureRMVMParams.VMOffer
        Write-Warning $NewITDAzureRMVMParams.VMSku
        Write-Warning $NewITDAzureRMVMParams.VMVnetName
        Write-Warning $NewITDAzureRMVMParams.VMSubnet
        Write-Warning $NewITDAzureRMVMParams.VMLocation
        Write-Warning $NewITDAzureRMVMParams.VMIP
        Write-Warning $NewITDAzureRMVMParams.VMCredential
        Write-Warning $NewITDAzureRMVMParams.VMAvailZone
        #>

        New-ITDAzureRMVM @NewITDAzureRMVMParams

        <#
        New-ITDAzureRMVM -VMFQDN $ComputerName `
            -VMSubscription $Subscription `
            -VMEnvironment $Environment `
            -VMOwner $VMOwner `
            -VMFunction $VMFunction `
            -VMSize $VMSize.Name `
            -VMOS $VMOS `
            -VMPublisher $Publisher `
            -VMOffer $Offer `
            -VMSku $Sku `
            -VMVNetName $VNet `
            -VMSubnet $VNetSubnet `
            -VMLocation $location `
            -VMIP $IPAddress `
            -VMCredential $VMCredential `
            -Verbose #>
       
        # wait for provisioning completion
        do {
        Start-Sleep -Seconds 15
        } while ( (Get-AzureRmVM -ResourceGroupName $ResourceGroup | Where-Object Name -Match $Name).ProvisioningState -eq "Creating")

        # check NIC
        $nic=Get-AzureRmNetworkInterface -ResourceGroupName $ResourceGroup | Where-Object Name -Match $Name
        $nic.IpConfigurations[0].PrivateIpAllocationMethod = "Static"
        $nic.IpConfigurations[0].PrivateIpAddress = $IPAddress
        Set-AzureRmNetworkInterface -NetworkInterface $nic

        #customize
        switch ($VMOS)
        {
            'Windows'
            {
                Invoke-AzureRmVMRunCommand -VMName $VMName `
                    -ResourceGroupName $ResourceGroup `
                    -CommandId 'RunPowerShellScript' `
                    -ScriptPath "S:\Distributed Systems\Systems\Azure\Scripts\WindowsCustomization.ps1" `
                    -AsJob
            }
            'Linux'
            {

            }
            Default
            {

            }
        }
    }       
    end 
    {

    }
}

<#
.SYNOPSIS
    Short description
.DESCRIPTION
    Long description
.EXAMPLE
    Example of how to use this cmdlet
.EXAMPLE
    Another example of how to use this cmdlet
.INPUTS
    Inputs to this cmdlet (if any)
.OUTPUTS
    Output from this cmdlet (if any)
.NOTES
    General notes
.COMPONENT
    The component this cmdlet belongs to
.ROLE
    The role this cmdlet belongs to
.FUNCTIONALITY
    The functionality that best describes this cmdlet
#>
function New-ITDAzureRMResourceGroup
{
    [CmdletBinding()]
    Param
    (
        [string[]]
        $AppName,
        
        [ValidateSet('prd','tst','infra')]
        [string[]]
        $Environment,

        [ValidateSet('centralus')]
        [string]
        $Location,

        [ValidateSet('VM','Network')]
        [string]
        $Ownership
    )
    
    begin
    {
        $Subscriptions=Get-AzureRmSubscription
    }
    
    process
    {
        ForEach($App in $AppName)
        {
            ForEach($Env in $Environment)
            {
                $VMOwner = $App.split('-')[0].ToLower()
                $VMFunction = (($App -replace "$VMOwner-") -replace "-").ToLower() -replace " "
                $ResourceGroupName = "rg-$VMOwner-$VMFunction-$Env"
                
                Write-Verbose "Resource Group Name: $ResourceGroupName"
             
                $Tags = @{
                    "ApplicationName" = $AppName;
                    "Environment" = $Environment;
                }

                switch ($Env)
                {
                    'infra'
                    {
                        $SubscriptionsToUse=@("infra01","infradr01")
                    }
                    'prd'
                    {
                        $SubscriptionsToUse=@("prd01","prddr01")
                    }
                    'tst'
                    {
                        $SubscriptionsToUse=@("tst01","tstdr01")
                    }
                    Default
                    {
                        Write-Error "invalid Environment" -ErrorAction Stop
                    }
                }

                ForEach($Sub in $SubscriptionsToUse)
                {
                    Set-AzureRmContext -Context ($Subscriptions | Where-Object Name -eq $Sub)
                    
                    Write-Verbose "Creating Resource Group $ResourceGroupName"
                    New-AzureRmResourceGroup -Name $ResourceGroupName -Location $Location -Tag $Tags

                    Write-Verbose "Setting $Ownership Permissions on Resource Group $ResourceGroupName"
                    Set-ITDAzureRMResourceGroupAssignment -Ownership $Ownership -ResourceGroup $ResourceGroupName
                }
            }
        }

    }
    
    end
    {
    }
}


<#
.SYNOPSIS
    Short description
.DESCRIPTION
    Long description
.EXAMPLE
    Example of how to use this cmdlet
.EXAMPLE
    Another example of how to use this cmdlet
.INPUTS
    Inputs to this cmdlet (if any)
.OUTPUTS
    Output from this cmdlet (if any)
.NOTES
    General notes
.COMPONENT
    The component this cmdlet belongs to
.ROLE
    The role this cmdlet belongs to
.FUNCTIONALITY
    The functionality that best describes this cmdlet
#>
function Find-ITDAzureRMVM
{
    [CmdletBinding()]
    Param
    (
        [string]
        $VMName
    )
    
    begin
    {

    }
    
    process
    {
        $search=@()
        $Hostname=$VMName.split('-')[1]
        $Environment=$VMName.split('-')[2]

        Get-AzureRmSubscription | ForEach-Object{
            $Subscription=$_
            Set-AzureRmContext $_ | Out-Null
            $search += Get-AzureRmVM | Where-Object Name -eq $VMName | select *,@{n='SubscriptionName';e={$Subscription.Name}}
        }

        If(@($search).count -eq 1)
        {
            Write-Output $search
        }
        else
        {
            $count = $search.count
            Write-Error ($count + "VMs found")
        }
    }
    end
    {
        
    }
}

<#
.SYNOPSIS
    Short description
.DESCRIPTION
    Long description
.EXAMPLE
    Example of how to use this cmdlet
.EXAMPLE
    Another example of how to use this cmdlet
.INPUTS
    Inputs to this cmdlet (if any)
.OUTPUTS
    Output from this cmdlet (if any)
.NOTES
    General notes
.COMPONENT
    The component this cmdlet belongs to
.ROLE
    The role this cmdlet belongs to
.FUNCTIONALITY
    The functionality that best describes this cmdlet
#>
function Set-ITDAzureRmVMBackup
{
    [CmdletBinding()]
    Param
    (
        [string[]]
        $VMName
    )
    
    begin
    {
        
    }
    
    process
    {
        ForEach($name in $VMName)
        {
            $Vault = $null
            $BackupPolicy = $null
            
            $vm = Find-ITDAzureRMVM -VMName $name -ErrorAction Stop

            Set-AzureRmContext $vm.SubscriptionName
            $Vault = Get-AzureRmRecoveryServicesVault -Name rs-infra-azbackup-prd-100
            Set-AzureRmRecoveryServicesVaultContext -Vault $Vault
            $BackupPolicy = Get-AzureRmRecoveryServicesBackupProtectionPolicy -Name "DefaultPolicy"
            Enable-AzureRmRecoveryServicesBackupProtection -Policy $BackupPolicy -Name $$vm.Name -ResourceGroupName $vm.ResourceGroupName
        }
    }
    
    end
    {

    }
}

function New-ITDAzureRMResourceGroupAll
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        # Subscription for the Resource Group
        [Parameter(Mandatory=$true)]
        [String]
        $Subscription,

        # Resource Group Name
        [Parameter(Mandatory=$true)]
        [string]
        $Name,

        # Ownership -- VM or Network
        [Parameter(Mandatory=$true)]
        [String]
        $Ownership,

        # Azure Region
        [Parameter(Mandatory=$true)]
        [string]
        $Location,

        # Application Name
        [Parameter(Mandatory=$true)]
        [string]
        $ApplicationName
    )

    Begin
    {
    Set-AzureRmContext $Subscription
    $TagHashTable = @{}
    $ApplicationNameKey = "ApplicationName"
    $TagHashTable.Add($ApplicationNameKey, $ApplicationName)
    }
    Process
    {
    New-AzureRmResourceGroup -Name $Name -Location $Location -Tag $TagHashTable
    Set-ITDAzureRMResourceGroupAssignment -Ownership $Ownership -ResourceGroup $Name
    }
    End
    {
    }
}