I have a Windows VM that can has an internet connection that acts as a tunnel into a VPN, and this VM is supposed to share this internet connection with the host. This works perfectly in principle: On that Windows VM, I have a network interface named `Outbound` which represents the VPN connection, and an interface named `Gateway` which represents the connection that is shared with the host. I use Windows Internet Connection Sharing (ICS) to provide routing to the `Gateway` interface via `Outbound`. For reasons unknown to me, however, this sometimes just breaks and the only way to get it running again is to simply disable ICS on the `Outbound` interface and re-enable it. Doing this through the UI every time became annoying, so I researched how to do it programmatically. There is [a great superuser answer](https://superuser.com/a/649183/222330) which provides _almost_ all the details you need, but not quite.
<a href="https://blag.nullteilerfrei.de/2024/06/26/programmatic-internet-connection-sharing/#more-5917" class="more-link">Do you want to know more?</a>
I am writing a backup script which is supposed to backup data to a remote server, encrypted, and run as a scheduled task on a Windows machine. If you want all of that, you will have to store the encryption key somewhere. Instead of storing the password in plaintext, I had the idea to use the [Data Protection API]. Initially worried that I might have to write a wrapper for [CryptProtectData] myself, I quickly found the decent looking github project [DPAPIbridge]. Ultimately however, I figured out that Powershell can do all things. Presenting `vault.ps1`:
```powershell
Param(
[string] $StoreSecret,
[Parameter(Mandatory=$True,Position=0)]
[string] $filename )
[void] [Reflection.Assembly]::LoadWithPartialName("System.Security")
$scope = [System.Security.Cryptography.DataProtectionScope]::CurrentUser
if ($StoreSecret -eq "") {
$data = Get-Content $filename
$ciphertext = [System.Convert]::FromBase64String($data)
$plaintext = [System.Security.Cryptography.ProtectedData]::Unprotect(
$ciphertext, $null, $scope )
[System.Text.UTF8Encoding]::UTF8.GetString($plaintext)
} else {
$plaintext = [System.Text.UTF8Encoding]::UTF8.GetBytes($StoreSecret)
$ciphertext = [System.Security.Cryptography.ProtectedData]::Protect(
$plaintext, $null, $scope )
[System.Convert]::ToBase64String($ciphertext) > $filename
}
```
This script can be run as `vault.ps1 [-StoreSecret SECRET] FILE`. If the optional argument is present, it will store a protected blob containing `SECRET` in `FILE`, otherwise it will read a blob of protected data from `FILE` and print the enclosed secret string.
[DPAPIbridge]: https://github.com/vincepare/DPAPIbridge
[Data Protection API]: https://msdn.microsoft.com/en-us/library/ms995355.aspx
[CryptProtectData]: https://msdn.microsoft.com/de-de/library/windows/desktop/aa380261(v=vs.85).aspx
[Borg]: https://borgbackup.readthedocs.io/en/1.1.2/usage/general.html?highlight=borg_passcommand#environment-variables